ULID Generator
Generate ULIDs — sortable unique identifiers with embedded timestamps for distributed systems
Generating ULIDs — Sortable Unique Identifiers
ULID (Universally Unique Lexicographically Sortable Identifier) combines a millisecond-precision timestamp with cryptographic randomness to create identifiers that are both globally unique and chronologically sortable. Unlike UUID v4 which is entirely random and unsortable, ULIDs preserve creation order when sorted alphabetically — making them ideal for database primary keys where insert ordering matters for index performance, and for distributed systems where time-ordered identifiers enable efficient range queries and pagination.
ULIDs use Crockford Base32 encoding to produce compact 26-character strings that are URL-safe, case-insensitive, and contain no special characters. The format dedicates the first 10 characters to a 48-bit millisecond timestamp and the remaining 16 characters to 80 bits of randomness, providing both temporal ordering and collision resistance. All generation happens client-side using the Web Crypto API for the random component.
ULID Structure and Encoding
A ULID is a 128-bit value encoded as 26 Crockford Base32 characters:
- Timestamp (48 bits / 10 chars): Milliseconds since Unix epoch — sortable until the year 10889
- Randomness (80 bits / 16 chars): Cryptographically random data for uniqueness within the same millisecond
Crockford Base32 uses characters 0-9 and A-Z excluding I, L, O, U to avoid ambiguity with digits 1, 0, and each other. This makes ULIDs safe for case-insensitive systems, readable in logs, and unambiguous when communicated verbally or in printed documentation.
The timestamp-first layout ensures that ULIDs generated later always sort after earlier ones — 01HXYZ... (generated today) always sorts after 01HWY... (generated yesterday) in any alphabetical or binary comparison.
Advantages Over UUID for Database Keys
ULIDs address specific pain points of UUID v4 as database primary keys:
- Index locality: New rows always append to the end of B-tree indexes rather than inserting at random positions, dramatically reducing page splits and write amplification
- Natural ordering:
SELECT * FROM events ORDER BY idreturns chronological order without a separatecreated_atcolumn - Range queries: Fetch all records from a specific time window using ID range comparison:
WHERE id > ulid_from_timestamp('2024-03-01') - Compactness: 26 characters vs 36 for UUID (no hyphens), saving storage in high-volume tables
- URL safety: No hyphens or special characters — ULIDs work directly in URL paths without encoding
Monotonic ULID Generation
When multiple ULIDs are generated within the same millisecond, monotonic mode ensures they remain ordered:
- Standard mode: Each ULID gets independent random bits — ordering within the same millisecond is undefined
- Monotonic mode: If the timestamp matches the previous ULID, the random component is incremented by 1 rather than regenerated — guaranteeing strict ordering even at sub-millisecond generation rates
Monotonic generation is important for high-throughput systems that may generate thousands of IDs per millisecond, where random ordering within a millisecond could violate application assumptions about ID progression.
Code Examples
ULID Generation and Timestamp Extraction
// Generate a ULID
const ulid = generateULID();
console.log(ulid); // "01HY5P2X8G0K3MNPQ7RSTV4W9Z"
// Extract timestamp from ULID
function extractTimestamp(ulid) {
const ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
const timeChars = ulid.slice(0, 10);
let timestamp = 0;
for (const char of timeChars) {
timestamp = timestamp * 32 + ENCODING.indexOf(char.toUpperCase());
}
return new Date(timestamp);
}
console.log(extractTimestamp(ulid));
// "2024-03-15T10:30:45.123Z"
// ULIDs sort chronologically
const ids = [
"01HY5P3000AAAAAAAAAAAAAA", // later
"01HY5P2X8G0K3MNPQ7RSTV4W", // earlier
];
ids.sort(); // Natural sort = chronological orderStandards & Specifications
- ULID Specification — Defines the ULID format, Crockford Base32 encoding, and monotonic generation behavior
Frequently Asked Questions
What is a ULID and how is it different from a UUID?
A ULID (Universally Unique Lexicographically Sortable Identifier) is a 26-character identifier encoded in Crockford Base32. Unlike UUID v4 which is fully random, ULIDs embed a millisecond-precision timestamp in the first 10 characters, making them naturally sortable by creation time while remaining globally unique.
Are ULIDs safe to use as database primary keys?
Yes. ULIDs are excellent database primary keys because their time-ordered nature improves B-tree index locality, reducing page splits and fragmentation compared to random UUIDs. They are especially well-suited for distributed systems where chronological ordering matters.
What is monotonic ordering in ULIDs?
When multiple ULIDs are generated within the same millisecond, monotonic ordering ensures each subsequent ULID is lexicographically greater than the previous one by incrementing the random component. This guarantees strict ordering even at sub-millisecond generation rates.
What is Crockford Base32 encoding?
Crockford Base32 is a base-32 encoding that uses 32 unambiguous characters (0-9 and A-Z excluding I, L, O, U) to avoid confusion between visually similar characters. This makes ULIDs easy to read, copy, and transmit without errors.