ULID Validator
Validate ULID format (26 Crockford-Base32 chars).
ULID validation: time-sortable identifiers without the UUID v4 pain
A ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier proposed by Alizain Feerasta in 2016 as a pragmatic alternative to UUID v4. The spec defines a fixed string form of 26 characters in Crockford Base32, encoding a 48-bit Unix-millisecond timestamp followed by 80 bits of randomness โ a real example looks like 01H7XBJX2VJF8Z5TQXM9RTPDC0.
The Crockford alphabet is the key trick: it deliberately excludes the visually ambiguous letters I, L, O and U, so a ULID can be dictated by phone, printed on a receipt, or scanned by OCR without ambiguity. Structural validation reduces to a single case-insensitive regex:
/^[0-9A-HJKMNP-TV-Z]{26}$/i
Anatomy of the 26 characters
- Chars 1โ10 โ 48-bit timestamp, milliseconds since the Unix epoch. Good until the year 10889.
- Chars 11โ26 โ 80 bits of cryptographic randomness. That is 1.21 ร 10ยฒโด distinct values per millisecond.
- Because timestamp comes first and the alphabet is ordered, lexicographic sort matches chronological order.
ORDER BY idis the same asORDER BY created_atโ no extra column needed. - The spec also defines a monotonic mode: if two ULIDs are generated in the same millisecond, the random portion of the second is incremented from the first, guaranteeing strict ordering with zero collisions.
ULID vs UUID v4 vs UUID v7
ULID vs UUID v4: v4 is 122 bits of pure randomness โ unsortable, which causes B-tree index fragmentation in Postgres and MySQL. ULID solves this by putting time first. ULID is also shorter as a string (26 vs 36 chars) and has no hyphens.
ULID vs UUID v7 (RFC 9562, 2024): both encode a millisecond timestamp + randomness in 128 bits, but v7 is now an IETF standard while ULID is a community spec. UUID v7 reuses the standard 8-4-4-4-12 hex form (36 chars); ULID uses Crockford Base32 (26 chars, no ambiguous letters). For new greenfield projects, UUID v7 is the safer choice for interoperability; ULID remains popular where the shorter string and human-friendly alphabet matter.
Storage, libraries and gotchas
In Postgres you typically store ULIDs as CHAR(26) or VARCHAR(26), sometimes as BYTEA(16) for compactness. Validation libraries in the wild: ulid on npm (by Eric Vallabh Minikel), python-ulid, ulid-rs in Rust. The default casing is uppercase, but most parsers accept lowercase as well โ case-insensitive comparison is the safest. The biggest operational gotcha is clock drift: if a server's clock jumps backwards, newly generated ULIDs will sort before older ones, breaking the time-ordered guarantee. Keep your NTP healthy.
Where ULID shines
- Distributed primary keys โ generate IDs on any node without coordination, still get index-friendly inserts.
- Event sourcing โ events sort naturally by time, no separate sequence required.
- Log correlation IDs โ copy-paste-friendly in a terminal, no ambiguous chars.
- IndexedDB keys โ sortable cursor traversal in the browser.
FAQ
Should ULID replace UUID in my new project? Yes if you index by ID and need time-ordering and your stack already has a ULID library. Otherwise pick UUID v7 โ it gives you the same sortability with a standardized format.
Is ULID case-sensitive? No. The canonical output is uppercase, but Crockford Base32 is case-insensitive on input; 01h7xbjx2vjf8z5tqxm9rtpdc0 decodes to the same bytes as the uppercase form.
How big is the collision risk? 80 bits of randomness per millisecond. To get a 50% collision probability in the same millisecond by birthday bound you would need around 1.2 billion ULIDs in that one millisecond โ practically impossible. Across milliseconds, the timestamp prefix guarantees uniqueness.
Does the timestamp leak information? Yes โ anyone reading a ULID can decode the millisecond of creation. If you publish IDs to untrusted users and need privacy of creation time, prefer UUID v4 or hash the ULID.
Related Tools
CPF Validator
Validate Brazilian CPF numbers instantly using the official algorithm. Useful for testing document validation in applications. No data sent to servers.
Batch CPF Validator
Validate a list of CPFs (one per line) and see which are valid and which are not. No data sent to servers.
Batch CNPJ Validator
Validate a list of CNPJs (one per line) with a summary of valid, invalid and total. No data sent to servers.