Reading:
UUID v4 vs v7: Which Should You Use as a Primary Key?

UUID v4 vs v7: Which Should You Use as a Primary Key?

Metamug

//: # ()

Need to generate or decode a UUID right now? Use our free UUID Generator & Inspector — create v4 or v7 UUIDs in bulk, or paste one in to see its version, variant, and embedded timestamp.

Why UUIDs exist

Auto-incrementing integer IDs are simple, but they leak information (a competitor can estimate your signup rate from sequential user IDs) and they don't work well when multiple systems need to generate IDs independently without coordinating — think distributed systems, offline-first mobile apps, or merging data from multiple databases. A UUID (Universally Unique Identifier) solves this: 128 bits, generated independently, collision probability low enough to ignore in practice.

But "UUID" isn't one format — it's a family, and the version you pick has real, measurable consequences for database performance.

UUID v4: fully random

A v4 UUID is 122 bits of randomness (the other 6 bits are fixed to mark version and variant). That randomness is exactly what makes it unpredictable and safe to expose publicly — but it's also the problem for databases.

Most relational databases (PostgreSQL, MySQL/InnoDB, SQL Server) store primary keys in a B-tree index, physically ordered by key value. Insert a random v4 UUID, and the database has to insert it into a random position in that tree — not append it to the end. At small scale this doesn't matter. At scale, it causes:

  • Page splits — the B-tree constantly reorganizes as random values land in the middle of already-full pages
  • Poor cache locality — recently-inserted rows end up scattered across the whole index rather than clustered together, so the "hot" working set doesn't fit in memory as well
  • Index bloat — fragmented pages waste disk space and slow down range scans

This is a well-documented, measurable problem — see Percona's benchmarks on UUID primary keys for real numbers on the throughput cost.

UUID v7: time-ordered

UUID v7 (standardized in RFC 9562 in 2024) fixes exactly this, by construction:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           unix_ts_ms                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          unix_ts_ms          |  ver  |       rand_a          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|                        rand_b                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The first 48 bits are a millisecond-precision Unix timestamp. Everything after that is still random (74 bits — plenty of entropy to avoid collisions), but because the leading bits are time-based, UUIDs generated later always sort after ones generated earlier. That single property means:

  • New rows are always inserted at the end of the B-tree, just like an auto-increment integer — no more random-position page splits
  • The UUID itself encodes roughly when the row was created, so you can eyeball creation order without a separate created_at lookup (though you should still keep one — the timestamp precision and clock trust model aren't a substitute for an actual timestamp column)
  • You still get the distributed-generation and non-guessability benefits of a real UUID, since 74 bits of randomness is still effectively uncollidable at any realistic scale

So which should you use?

UUID v4 UUID v7
Sortable by creation time No Yes
Index-friendly for DB primary keys No (fragmentation) Yes (append-like)
Fully unpredictable Yes Partially (timestamp is visible)
Best for Public-facing tokens, session IDs, anything where hiding when it was created matters Primary keys, especially at scale

If you're choosing a primary key type for a new table today and your database and drivers support it, v7 is the better default — you get UUID's distributed-generation benefits without the B-tree performance tax. Reach for v4 specifically when you need creation time to stay hidden, like a password-reset token or an API key.

Try it

Generate v4 or v7 UUIDs in bulk, or paste one in to decode its embedded timestamp, with the UUID Generator & Inspector — entirely client-side.



Icon For Arrow-up
Comments

Post a comment