almessadi.
Back to Index

UUIDv4 vs ULID: What Actually Matters for Database Writes_

Random identifiers are convenient, but they are not free. If write locality matters, compare UUIDv4 with time-ordered identifiers such as ULID or UUIDv7.

PublishedApril 2, 2024
Reading Time6 min read

UUIDv4 is a good default when you need unique identifiers that can be generated independently across services.

The problem is not that UUIDv4 is "wrong". The problem is that fully random identifiers have weaker write locality than sequential or time-ordered identifiers when used in indexes.

That matters once write volume is high enough.

Why Random IDs Change Index Behavior

PostgreSQL commonly uses B-tree indexes for primary keys.

With an append-friendly identifier, new rows tend to land near the end of the index. With a random identifier like UUIDv4, inserts land throughout the key space.

That can lead to:

  • more page splits
  • worse cache locality
  • more write amplification under heavy insert load

This is not a moral failing of UUIDv4. It is a consequence of randomness.

When You Notice It

Many systems will never care.

If the table is modest in size or write throughput is moderate, UUIDv4 is often fine.

You start caring when:

  • the table is large
  • inserts are hot
  • the primary key is also the clustered access pattern for adjacent systems

That is the point where time-ordered ids become attractive.

ULID and UUIDv7

ULID is popular because it is lexicographically sortable and still decentralized. It improves locality compared with UUIDv4.

Today, UUIDv7 is also worth serious attention because it provides time-ordered UUIDs in a standardized format.

That leads to a more modern rule of thumb:

  • use UUIDv4 when randomness is fine and the workload is not sensitive
  • use ULID or UUIDv7 when index locality and ordering matter

The Application Trade-Off

Identifier choice is not just a database decision.

You are also choosing:

  • sort behavior
  • string length and encoding
  • interoperability with libraries and databases
  • human readability in logs and URLs

That is why there is no universal winner.

A Useful Recommendation

If you are starting a new system and want time-ordered identifiers, prefer a standardized format where possible. That usually means evaluating UUIDv7 first, with ULID still being a pragmatic option when its ecosystem fit is better for your stack.

If you already use UUIDv4 and the database is healthy, do not migrate just because a blog post said random ids are bad. Measure the actual workload first.

Further Reading