ULID: The Sortable Alternative to UUID
Everything you need to know about ULIDs — Universally Unique Lexicographically Sortable Identifiers. How they work, when to use them, and how they compare to UUIDs.
What Is a ULID?
A ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier designed as a drop-in replacement for UUID that adds lexicographic sortability. Created by Alizain Feerasta, ULIDs solve the primary weakness of UUID v4: the inability to sort by creation time.
A ULID looks like this:
01ARZ3NDEKTSV4RRFFQ69G5FAV
It’s 26 characters long, encoded in Crockford’s Base32, and encodes both a timestamp and randomness in a single, compact string.
Structure
A ULID consists of two components packed into 128 bits:
01ARZ3NDEK TSV4RRFFQ69G5FAV
|----------| |----------------|
Timestamp Randomness
48 bits 80 bits
10 chars 16 chars
Timestamp (48 bits / 10 characters)
The first 48 bits encode a Unix timestamp in milliseconds. This gives:
- Resolution: 1 millisecond
- Range: Until the year 10889 (more than enough)
- Sorting: Because the timestamp is the most significant bits, ULIDs naturally sort by creation time
Randomness (80 bits / 16 characters)
The remaining 80 bits are filled with cryptographically secure random data. This provides:
- 2^80 possible values per millisecond (~1.2 × 10^24)
- Collision probability within the same millisecond is astronomically low
Crockford’s Base32 Encoding
ULIDs use Crockford’s Base32 encoding, which has several advantages over standard hex or Base64:
Alphabet: 0123456789ABCDEFGHJKMNPQRSTVWXYZ
Key design decisions:
- No I, L, O, U — avoids confusion with 1, l, 0, and offensive words
- Case-insensitive —
01ARZ3NDEK=01arz3ndek - URL-safe — no special characters
- Human-readable — designed to be easy to read, type, and communicate verbally
Monotonic Sort Order
When multiple ULIDs are generated within the same millisecond, the random component is incremented rather than regenerated. This guarantees strict monotonic ordering even within the same timestamp:
01ARZ3NDEKTSV4RRFFQ69G5FAV ← t=1000ms, random=X
01ARZ3NDEKTSV4RRFFQ69G5FAW ← t=1000ms, random=X+1
01ARZ3NDEKTSV4RRFFQ69G5FAX ← t=1000ms, random=X+2
This is particularly important for database operations where insert order matters.
ULID vs UUID Comparison
| Feature | ULID | UUID v4 | UUID v7 |
|---|---|---|---|
| Length (text) | 26 chars | 36 chars | 36 chars |
| Encoding | Crockford Base32 | Hex + hyphens | Hex + hyphens |
| Sortable by time | Yes | No | Yes |
| Timestamp embedded | Yes (48-bit ms) | No | Yes (48-bit ms) |
| Random bits | 80 | 122 | 74 |
| Possible values | 2^80 per ms (~1.2 × 10^24) | 2^122 total (~5.3 × 10^36) | 2^74 per ms (~1.9 × 10^22) |
| Case-sensitive | No | No | No |
| URL-safe | Yes | Yes (with hyphens) | Yes (with hyphens) |
| Human-readable | Better | Good | Good |
| Standard | Community spec | RFC 9562 | RFC 9562 |
When to Choose ULID Over UUID
- Compact representation — 26 chars vs 36
- Better readability — no hyphens, no ambiguous characters
- Monotonic guarantee — strict ordering within same millisecond
- URL-friendliness — no special characters at all
When to Choose UUID Over ULID
- RFC standardization — UUIDs are an IETF standard (RFC 9562)
- Broader ecosystem support — native UUID types in most databases
- Multiple versions — deterministic (v3/v5), timestamp (v1/v6/v7), custom (v8)
- More random bits — v4 has 122 random bits vs ULID’s 80
Database Considerations
As Primary Keys
ULIDs make excellent primary keys because:
- Sequential inserts — monotonic ordering means new rows are always appended, not inserted randomly into the B-tree
- No hotspots — unlike auto-increment, ULIDs don’t create contention on a single counter
- Distributed generation — no coordination needed between nodes
- Embedded timestamp — free “created_at” metadata
Storage
Store ULIDs as:
- Binary(16) — most efficient (128 bits = 16 bytes)
- CHAR(26) — human-readable, slightly larger
- UUID type — convert ULID to UUID binary format for databases with native UUID support
Extracting the Timestamp
You can extract the creation timestamp from any ULID:
| |
What Is a CSPRNG?
A CSPRNG (Cryptographically Secure Pseudo-Random Number Generator) is a random number generator that produces output suitable for use in cryptography — meaning the output is statistically indistinguishable from true randomness and computationally infeasible to predict, even if an attacker knows previous outputs.
Regular random number generators (like JavaScript’s Math.random()) use simple algorithms that are fast but predictable. If an attacker observes enough outputs, they can reverse-engineer the internal state and predict future values. This is unacceptable for generating unique identifiers, passwords, or encryption keys.
A CSPRNG solves this by drawing entropy from unpredictable physical sources — hardware interrupts, CPU timing jitter, mouse movements, and other environmental noise — then mixing it through cryptographic algorithms to produce uniformly distributed, unpredictable output.
In browsers, the CSPRNG is available through the Web Crypto API:
| |
All Safe Pass Guru generators use crypto.getRandomValues() exclusively — Math.random() is never used.
Security Considerations
- Like UUIDs, ULIDs are not secrets — don’t use them as authentication tokens
- The embedded timestamp reveals when the ID was created — consider whether this is acceptable for your use case
- The monotonic increment within the same millisecond makes successive ULIDs predictable within that window
- Always use a CSPRNG for the random component — our tool uses
crypto.getRandomValues()
When to Use ULIDs
Use ULIDs when you need:
- Compact, sortable, unique identifiers
- No external dependencies or coordination
- Clean URLs and human-friendly IDs
- Database-friendly sequential inserts
Consider alternatives when:
- You need RFC-standardized identifiers (use UUID v7)
- You need deterministic IDs from names (use UUID v5)
- You need maximum random bits (use UUID v4)
- Your database has native UUID support with optimized indexing