Skip to main content

2026-03-04

6 min

By Formatho Editorial

Why You Should Use ULIDs Instead of UUIDs in Your Database

ULIDUUIDDatabases
Programming code on screen representing data encoding and transformation

Same job, different shape

Both are 128-bit identifiers with negligible collision risk. The difference is structure: UUIDv4 is 122 random bits; a ULID is 48 bits of millisecond timestamp + 80 random bits, encoded as 26 uppercase alphanumeric characters (Crockford base32). That timestamp changes everything about how each behaves in a database.

The index locality problem

Random UUIDs inserted into a B-tree index land at random leaf positions: every insert touches a random page, pages split unevenly, the cache hit rate drops, and on very large tables the index fragments. ULIDs are time-ordered, so inserts append to the right edge of the index — sequential-ish writes, better cache behavior, and naturally sorted by creation time. This is why event stores, log aggregators, and DynamoDB-style systems (KSUIDs, Snowflake IDs — same idea) use time-ordered IDs.

Trade-offs

UUIDv4ULID
Sortabilitymeaningless ordercreation order
Index behaviorrandom writesappend-mostly
Unpredictabilityopaqueembeds creation time
Length (text)36 chars26 chars
Case/formathex + dashesCrockford base32, canonically uppercase
StandardizationRFC 4122 everywherecommunity spec, many impls

When the timestamp leaks

ULIDs expose creation time — fine for a comment ID, questionable for an order ID when volume is business-sensitive (competitors can estimate your throughput from IDs), and outright wrong for capability URLs or reset tokens, which must be unguessable. The random portion is 80 bits — enough for collision resistance at normal scale, but not for unguessability against a targeted guesser; use random UUIDs or longer tokens there.

Monotonicity within a millisecond

Two ULIDs generated in the same millisecond must increment their random part to stay ordered — implementations differ (some offer a monotonic factory), so concurrent generators on one host need a coordination choice. Also note the 48-bit timestamp overflows in 10889 AD — someone else's problem.

Generate and compare both formats locally in the ULID Generator and UUID Generator.

Formatho Editorial — written and maintained by the team behind formatho.com, a library of free, privacy-first developer tools that run entirely in your browser. Every guide is tested against the tools it describes. Corrections and suggestions: github.com/formatho.