CUID2
Generate a CUID2 string. CUID2 is a secure, collision-resistant identifier that hashes multiple entropy sources using SHA3-512. Unlike time-ordered IDs (ULID, UUID v7), CUID2 prevents enumeration attacks by making IDs non-predictable.Import
Function Signature
Basic Usage
Options
Configuration options for CUID2 generation
Static Methods
isValid()
Validate whether a value is a valid CUID2 string (type guard).Value to validate
Type predicate:
true if the value is a valid CUID2 string, false otherwise- Must be a string
- Length must be between 2 and 32 characters
- Must match the pattern:
/^[a-z][0-9a-z]+$/ - First character must be lowercase letter (
a-z) - Remaining characters must be lowercase alphanumeric (
0-9a-z)
Security Features
SHA3-512 Hashing
CUID2 hashes multiple entropy sources using SHA3-512:- Timestamp (
Date.now()) - Random salt
- Monotonic counter
- System fingerprint (based on global environment)
Monotonic Counter
An internal counter is incremented with each ID generation:- Initialized with cryptographically secure random value (0 to 476,782,367)
- Provides ~29 bits of initial entropy to prevent cross-process collisions
System Fingerprint
A unique fingerprint is generated based on:- Global object keys (
Object.keys(globalThis)) - Additional random entropy
Length and Entropy
| Length | Bits of Entropy (approx) | Collision Probability |
|---|---|---|
| 10 | ~52 bits | 1 in 4.5 quadrillion |
| 16 | ~83 bits | 1 in 9.7 septillion |
| 24 (default) | ~124 bits | 1 in 21.3 undecillion |
| 32 | ~165 bits | Astronomically low |
Advanced Usage
Deterministic Generation (Testing)
Provide custom random bytes for reproducible IDs:Variable Length IDs
Adjust length based on your use case:State Management
CUID2 maintains module-level state for:- Counter: Incremented on each call for uniqueness
- Fingerprint: Generated once on first call and cached
- In serverless/edge functions with warm starts, state persists between invocations
- For isolated state in tests, consider mocking or resetting the module
Format
CUID2 uses a Base36 alphabet (0-9a-z) for URL-safe, case-insensitive IDs:
- First character: Always a lowercase letter (
a-z) for safe use in various contexts - Remaining characters: Lowercase alphanumeric (
0-9a-z)
Binary Representation
Note: Unlike UUID and ULID, CUID2 does not providetoBytes()/fromBytes() because it is a string-native format with no canonical binary representation.
CUID2 is designed as a hash-based string identifier. While you could convert the Base36 string to bytes, there’s no standardized binary format, and the conversion would lose the semantic meaning of the ID.
Errors
Thrown when options are invalid:
- Code:
CUID2_LENGTH_OUT_OF_RANGE- Length must be 2-32 - Code:
CUID2_RANDOM_BYTES_EMPTY- Random byte array cannot be empty
Type Definitions
Performance
CUID2 is optimized for security over speed:- SHA3-512 hashing adds computational overhead
- Internal random pool for efficient random number generation
- Fingerprint is generated once and cached
@paralleldrive/cuid2 npm package.
Use Cases
CUID2 is ideal when you need:- Non-enumerable IDs: Prevent users from guessing other IDs
- API tokens: Secure, unpredictable tokens
- Public-facing IDs: User IDs, order IDs where enumeration is a concern
- Distributed systems: Collision-resistant without coordination
- Time-ordered database indexes: Use UUID v7 or ULID instead
- Ultra-high throughput: CUID2’s hashing is slower than pure random IDs
Migration from CUID (v1)
CUID2 is not backward-compatible with CUID (v1):- Different format (no timestamp prefix)
- Different hashing algorithm (SHA3-512 vs MD5)
- Improved collision resistance
- Better security guarantees
