ULID Generator
Generate ULID identifiers
Why use an ULID instead of an UUID?
ULIDs offer several advantages over UUIDs:
- Lexicographically sortable
- Better performance in DBs
- Shorter and readable (Base32)
Structure of an ULID
An ULID consists of 26 characters:
ULID combines a 48-bit timestamp with 80 bits of randomness, producing IDs that are both unique and chronologically sortable.
What is a ULID?
A ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier designed to be both globally unique and time-ordered. Created by Alizain Feerasta in 2016, ULIDs address a key limitation of UUIDs: random UUIDs (v4) are not sortable, which causes performance problems when used as database primary keys.
A ULID encodes a Unix timestamp in milliseconds in its most significant bits, followed by cryptographically random data. This means ULIDs generated later are always lexicographically greater than earlier ones — you can sort them as strings and get chronological order for free.
ULIDs are represented as 26-character strings using Crockford Base32 encoding, making them URL-safe, case-insensitive, and more compact than the 36-character UUID format.
ULID Structure
A ULID is 128 bits total, split into two components:
The timestamp occupies the first 48 bits (10 Crockford Base32 characters). It stores the number of milliseconds since Unix epoch (January 1, 1970). This gives ULIDs a valid range until approximately the year 10889.
The randomness occupies the remaining 80 bits (16 characters). When multiple ULIDs are generated within the same millisecond, implementations typically increment the random portion monotonically to preserve sort order within the same timestamp.
Crockford Base32 Encoding
ULIDs use Crockford Base32, an encoding alphabet designed by Douglas Crockford that is optimized for human readability:
0123456789ABCDEFGHJKMNPQRSTVWXYZ
Four letters are deliberately excluded:
- I — confused with
1orl - L — confused with
1orI - O — confused with
0 - U — can form accidental profanity
This makes ULIDs safer to read aloud, transcribe manually, and use in URLs. The encoding is case-insensitive, so 01ARZ3NDEK and 01arz3ndek represent the same value.
ULID vs UUID vs NANOID
| Property | UUID v4 | ULID | NANOID | UUID v7 |
|---|---|---|---|---|
| Size | 128 bits | 128 bits | Configurable (default 126 bits) | 128 bits |
| Text length | 36 chars | 26 chars | 21 chars (default) | 36 chars |
| Encoding | Hex + hyphens | Crockford Base32 | URL-safe Base64 | Hex + hyphens |
| Sortable | No | Yes (timestamp) | No | Yes (timestamp) |
| Timestamp | No | 48-bit ms | No | 48-bit ms |
| Monotonic | No | Within same ms | No | Within same ms |
| Standard | RFC 4122 | Spec (community) | Spec (community) | RFC 9562 |
| Ecosystem | Universal | Growing | JavaScript-centric | Growing |
When to Choose ULID
Choose ULID when you need sortable, compact identifiers and are working in an environment where the ULID spec is well-supported. ULIDs are especially compelling for:
- Event sourcing — Events must be ordered. ULID timestamps provide natural ordering without a separate sequence number.
- Distributed databases — Cassandra, DynamoDB, and other distributed stores benefit from time-ordered partition keys that avoid hotspots.
- Message queues — ULIDs as message IDs enable consumers to process messages in approximate chronological order.
- Log aggregation — When merging logs from multiple services, ULID-based log IDs sort correctly across sources.
Choose UUID v7 instead if you need maximum ecosystem compatibility (UUID libraries exist in every language) and the 36-character format is acceptable. UUID v7 provides the same time-ordering benefit in a standardized RFC format.
Choose NANOID if you need the shortest possible identifier and sortability is not important — for example, URL shorteners or client-side generated keys where compactness matters most.
Monotonic ULIDs
When generating multiple ULIDs within the same millisecond, a naive implementation could produce IDs with identical timestamps and independent random portions — which might not sort in generation order. Monotonic ULIDs solve this by incrementing the random component by 1 for each ULID generated within the same millisecond.
This guarantees that even sub-millisecond generation preserves strict ordering. Most production ULID libraries implement monotonic generation by default.
The trade-off is that monotonic ULIDs generated in the same millisecond have a slight correlation in their random portions. In practice, this has no impact on uniqueness — the 80-bit random space is vast enough that even sequential increments within a single millisecond will never overlap across different generators.
Common Use Cases
- Database primary keys: ULIDs provide the uniqueness of UUIDs with the index-friendly ordering of auto-increment integers
- Event IDs in event-driven architectures: Natural chronological ordering simplifies event replay, debugging, and audit trails
- Distributed system correlation: Independent services generate sortable IDs without coordination, enabling cross-service log correlation
- Time-series data: The embedded timestamp allows rough time-based queries on the ID itself, without a separate timestamp column
- API resource identifiers: 26 characters is more compact than UUID’s 36, and the case-insensitive encoding avoids URL issues
Try These Examples
A valid ULID — 26 characters encoded in Crockford Base32. The first 10 characters represent a 48-bit Unix timestamp in milliseconds. The remaining 16 characters are cryptographically random.
01ARZ3NDEKTSV4RRFFQ69G5FAV ULIDs generated at different times are naturally sortable. The timestamp portion increments, so string sorting equals chronological sorting. No special comparator needed.
01ARZ3NDEK0000000000000000 < 01ARZ3NFHK0000000000000000