ULID and UUID both produce 128-bit unique identifiers, but they were designed with different priorities. ULID prioritizes lexicographic time ordering and a compact text form, while UUID is the older, universally supported standard. UUID v7 narrows most of the practical gap.
Key takeaways
- Both are 128-bit identifiers under the hood.
- ULID sorts by creation time and uses a shorter Base32 text form.
- UUID v7 gives UUIDs the same time-ordering benefit while staying standard.
The core difference
A ULID is a 128-bit value made of a 48-bit millisecond timestamp followed by 80 random bits, encoded as 26 Crockford Base32 characters. A UUID is also 128 bits, but it is written as 36 hexadecimal characters with hyphens and comes in several versions.
ULID was created specifically to be sortable by time and friendly in URLs and logs. Classic random UUID v4 is neither sortable nor compact, which is what motivated ULID in the first place.
Where UUID v7 changes the story
UUID v7 puts a Unix millisecond timestamp at the front of the UUID, giving it the same natural time ordering that made ULID attractive. If your main reason for considering ULID was sortable primary keys, UUID v7 achieves that while staying inside the widely supported UUID standard and native database UUID types.
ULID still wins on text length and Base32 readability, but UUID v7 is usually the safer default because tooling, database types and libraries already understand UUIDs everywhere.
| Aspect | UUID v7 | ULID |
|---|---|---|
| Bits | 128 | 128 |
| Text length | 36 chars (hex + hyphens) | 26 chars (Base32) |
| Time sortable | Yes | Yes |
| Standard / native DB type | Yes | Rarely native |
| Ecosystem support | Universal | Growing |
How to choose
Choose UUID (v7 for ordered keys, v4 for opaque random IDs) when you want maximum compatibility, native database support and the least friction. Choose ULID when a compact, URL-friendly, lexicographically sortable string is a first-class requirement and your stack already handles ULIDs cleanly.
Whichever you pick, keep a database uniqueness constraint and treat the identifier as an identifier, not a secret.