Last Updated: 3/9/2026
Performance
Nano ID is optimized for production use with excellent performance characteristics.
Benchmark Results
Secure Generators
crypto.randomUUID 7,619,041 ops/sec (fastest)
uuid v4 7,436,626 ops/sec
@napi-rs/uuid 4,730,614 ops/sec
uid/secure 4,729,185 ops/sec
@lukeed/uuid 4,015,673 ops/sec
nanoid 3,693,964 ops/sec ← Good balance
customAlphabet 2,799,255 ops/sec
nanoid for browser 380,915 ops/sec
secure-random-string 362,316 ops/sec
uid-safe.sync 354,234 ops/sec
shortid 38,808 ops/sec (slowest)Non-Secure Generators
uid 11,872,105 ops/sec (fastest)
rndm 2,308,044 ops/sec
nanoid/non-secure 2,226,483 ops/secTest configuration: Framework 13 7840U, Fedora 39, Node.js 21.6
Performance Analysis
Why Nano ID is Fast Enough
At 3.7M operations/second, Nano ID generates:
- 3,700,000 IDs per second
- 222 million IDs per minute
- 13 billion IDs per hour
In practice: Even high-traffic applications rarely need >1000 IDs/sec, making Nano ID’s performance more than adequate.
Why Not Fastest?
Nano ID prioritizes bundle size and URL-safety over raw speed:
| Library | Speed | Size | URL-Safe |
|---|---|---|---|
| crypto.randomUUID | 7.6M/s | Native | ❌ (needs encoding) |
| uuid v4 | 7.4M/s | 423 bytes | ❌ (hyphens) |
| nanoid | 3.7M/s | 118 bytes | ✅ |
Trade-off: 2x slower but 3.5x smaller and URL-safe.
Optimization Techniques
1. Random Pool Architecture
Nano ID uses pooled random generation to minimize system calls:
const POOL_SIZE_MULTIPLIER = 128
function fillPool(bytes) {
if (!pool || pool.length < bytes) {
// Generate 128x requested size
pool = Buffer.allocUnsafe(bytes * 128)
crypto.getRandomValues(pool)
}
}Impact: 128 IDs generated per system call instead of 1.
2. Bitwise Operations
Uses fast bitwise AND for alphabet mapping:
// Fast: bitwise AND (single CPU cycle)
id += urlAlphabet[pool[i] & 63]
// Slow: modulo (multiple CPU cycles)
id += urlAlphabet[pool[i] % 64]3. Compact Code
Smaller code = better CPU cache utilization:
- 118 bytes fits entirely in L1 cache
- No function call overhead
- Inline operations
Performance Comparison
vs UUID v4
import { randomUUID } from 'crypto'
import { nanoid } from 'nanoid'
// UUID: 7.4M ops/sec, 423 bytes
const uuid = randomUUID() // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
// Nano ID: 3.7M ops/sec, 118 bytes
const id = nanoid() // "V1StGXR8_Z5jdHi6B-myT"When to use UUID:
- Maximum performance needed
- UUID format required by system
- Bundle size doesn’t matter
When to use Nano ID:
- Bundle size matters (web apps)
- URL-safe IDs needed
- Shorter IDs preferred
vs customAlphabet
import { nanoid, customAlphabet } from 'nanoid'
// Default: 3.7M ops/sec
const id1 = nanoid()
// Custom: 2.8M ops/sec (24% slower)
const nanoid2 = customAlphabet('0123456789', 10)
const id2 = nanoid2()Why slower: Rejection sampling for non-power-of-2 alphabets.
vs Non-Secure
import { nanoid } from 'nanoid'
import { nanoid as insecure } from 'nanoid/non-secure'
// Secure: 3.7M ops/sec
const id1 = nanoid()
// Non-secure: 2.2M ops/sec (40% slower!)
const id2 = insecure()Paradox: Non-secure is slower because:
- No pooling (calls Math.random() per character)
- Secure version batches system calls
Real-World Performance
HTTP Server
import { nanoid } from 'nanoid'
import express from 'express'
const app = express()
app.post('/users', (req, res) => {
const user = {
id: nanoid(), // ~270 nanoseconds
...req.body
}
// Database insert: ~5-50 milliseconds
// Network latency: ~10-100 milliseconds
// ID generation is 0.0005% of total request time
})Conclusion: ID generation is negligible compared to I/O.
Batch Generation
import { nanoid } from 'nanoid'
// Generate 10,000 IDs
const start = Date.now()
const ids = Array(10000).fill(null).map(() => nanoid())
const elapsed = Date.now() - start
console.log(`Generated 10,000 IDs in ${elapsed}ms`)
// Output: ~2.7ms (270 nanoseconds per ID)Optimization Tips
✅ Do: Reuse Custom Alphabet Generator
import { customAlphabet } from 'nanoid'
// ✅ Good: Create once
const nanoid = customAlphabet('0123456789', 10)
for (let i = 0; i < 10000; i++) {
const id = nanoid() // Fast
}❌ Don’t: Recreate Generator
import { customAlphabet } from 'nanoid'
// ❌ Bad: Creates generator 10,000 times
for (let i = 0; i < 10000; i++) {
const nanoid = customAlphabet('0123456789', 10)
const id = nanoid() // Slow
}✅ Do: Use Power-of-2 Alphabets
import { customAlphabet } from 'nanoid'
// ✅ Fast: 64 chars = 2^6 (no rejection)
const fast = customAlphabet(
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
21
)
// ❌ Slower: 30 chars (rejection sampling needed)
const slow = customAlphabet('0123456789ABCDEFGHIJKLMNOPQR', 21)✅ Do: Batch Operations
import { nanoid } from 'nanoid'
// ✅ Good: Batch database inserts
const users = Array(1000).fill(null).map((_, i) => ({
id: nanoid(),
name: `User ${i}`
}))
await db.users.insertMany(users) // Single queryWhen Performance Matters
High-Throughput Systems
If generating >1M IDs/second:
import { randomUUID } from 'crypto'
// Use crypto.randomUUID for maximum speed
const id = randomUUID()Embedded Systems
If CPU-constrained:
import { nanoid } from 'nanoid/non-secure'
// Use non-secure for lower CPU usage
// (but only if security isn't critical)
const id = nanoid()Bundle Size Critical
If every byte matters:
import { nanoid } from 'nanoid'
// Nano ID: 118 bytes
// UUID: 423 bytes
// Savings: 305 bytes per importProfiling
Measure ID Generation
import { nanoid } from 'nanoid'
const iterations = 100000
const start = performance.now()
for (let i = 0; i < iterations; i++) {
nanoid()
}
const elapsed = performance.now() - start
const opsPerSec = (iterations / elapsed) * 1000
console.log(`${opsPerSec.toFixed(0)} ops/sec`)Compare Alternatives
import { nanoid } from 'nanoid'
import { randomUUID } from 'crypto'
function benchmark(fn, name, iterations = 100000) {
const start = performance.now()
for (let i = 0; i < iterations; i++) fn()
const elapsed = performance.now() - start
const opsPerSec = (iterations / elapsed) * 1000
console.log(`${name}: ${opsPerSec.toFixed(0)} ops/sec`)
}
benchmark(() => nanoid(), 'nanoid')
benchmark(() => randomUUID(), 'crypto.randomUUID')See Also
- How It Works - Algorithm details
- Security - Security vs performance trade-offs
- Benchmark source