Benchmarks, optimization tips, and bundle size comparison
Uniku is designed for performance-sensitive contexts like ORMs and high-throughput services. This guide covers benchmarks, bundle size, and optimization strategies.
The npm ulid package has performance bottlenecks in Base32 encoding:
// ❌ Slow: String concatenation in looplet str = ''for (let i = 0; i < 26; i++) { str += ALPHABET[value & 0x1f] value = value >> 5}// ✅ Fast: Pre-allocated array with direct indexingconst chars = new Array(26)for (let i = 0; i < 26; i++) { chars[i] = ALPHABET[value & 0x1f] value = value >> 5}return chars.join('')
Uniku uses optimized algorithms throughout:
Pre-allocated arrays instead of string concatenation
The @paralleldrive/cuid2 package creates new random bytes for every operation. Uniku pools random bytes:
// ❌ Slow: Generate fresh random bytes every callfunction cuid2() { const random = new Uint8Array(32) crypto.getRandomValues(random) // ... use random bytes}// ✅ Fast: Pool random bytes, refill when depletedconst pool = new Uint8Array(4096)let poolOffset = 0function cuid2() { if (poolOffset + 32 > pool.length) { crypto.getRandomValues(pool) poolOffset = 0 } const random = pool.subarray(poolOffset, poolOffset + 32) poolOffset += 32 // ... use random bytes}
Uniku uses separate entry points instead of barrel exports:
// ✅ Good: Only bundles UUID v7 code (~1.1 KB)import { uuidv7 } from 'uniku/uuid/v7'// ❌ Bad: Would bundle everything if we had a barrel export// import { uuidv7 } from 'uniku' // Not available!
Bundle Impact Example:
// Scenario 1: Only use UUID v7import { uuidv7 } from 'uniku/uuid/v7'const id = uuidv7()// Bundle size: ~1.1 KB// Scenario 2: Use UUID v7 and Nanoidimport { uuidv7 } from 'uniku/uuid/v7'import { nanoid } from 'uniku/nanoid'const id1 = uuidv7()const id2 = nanoid()// Bundle size: ~2.0 KB (1.1 KB + 0.9 KB)
When generating many IDs, write directly to a buffer:
import { uuidv7 } from 'uniku/uuid/v7'// Generate 100 UUIDs into a single bufferconst buffer = new Uint8Array(100 * 16)for (let i = 0; i < 100; i++) { uuidv7(undefined, buffer, i * 16)}// Convert to strings later if neededfor (let i = 0; i < 100; i++) { const bytes = buffer.subarray(i * 16, (i + 1) * 16) const str = uuidv7.fromBytes(bytes)}
Writing to buffers is faster when you need to serialize IDs later (e.g., storing in a database or sending over the network).
import { uuidv7 } from 'uniku/uuid/v7'class User { id = uuidv7() // Called on every new User() email: string createdAt = new Date()}// Creating 1000 usersconst users = Array.from({ length: 1000 }, () => new User())
Uniku’s performance optimizations shine in these scenarios.
// All runtimes support globalThis.cryptoconst crypto = globalThis.crypto// Node.js (v16+)import { uuidv7 } from 'uniku/uuid/v7'const id = uuidv7()// Denoimport { uuidv7 } from 'npm:uniku/uuid/v7'const id = uuidv7()// Bunimport { uuidv7 } from 'uniku/uuid/v7'const id = uuidv7()// Cloudflare Workersimport { uuidv7 } from 'uniku/uuid/v7'const id = uuidv7()// Browsersimport { uuidv7 } from 'uniku/uuid/v7'const id = uuidv7()
No Node.js-specific APIs means zero compatibility issues across runtimes.
✅ Use the default (no options) for fastest generation
✅ Choose the right format for your use case
✅ Write to buffers for batch operations
✅ Reuse buffers when possible
✅ Import only what you need (tree-shaking)
❌ Don’t pass custom options in hot paths
❌ Don’t use string concatenation for batch operations
Bottom line: Uniku is fast enough for any use case. For most applications, the performance difference between ID formats is negligible compared to network and database latency.