UUID v4 vs v7: Which Should You Use for Database Keys?
UUID v4 is random; UUID v7 is time-ordered. Learn how each is built, why v4 fragments B-tree indexes, and when v7 is the better primary key.
For years, "use a UUID" meant version 4: 122 random bits formatted as 36 hex characters. Version 7, standardized in RFC 9562 (2024), keeps the same shape but front-loads a timestamp. The difference sounds minor and turns out to matter a great deal for database performance.
The common format
Every UUID is 128 bits, displayed as 8-4-4-4-12 hex groups:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Mis the version nibble:4for v4,7for v7.Nencodes the variant; for both versions it is one of8,9,a, orb.
Everything else depends on the version.
UUID v4: pure randomness
f47ac10b-58cc-4372-a567-0e02b2c3d479
Apart from the 6 fixed bits (version and variant), all 122 bits come from a cryptographically secure random source. Two properties follow:
- Collision is a non-issue. You would need to generate about 2.7 × 10¹⁸ UUIDs to have a 50% chance of a single duplicate.
- There is no order. Two v4 UUIDs generated a microsecond apart are unrelated. Sorting them is meaningless.
Generate a few with the UUID v4 Generator and notice that nothing about them changes over time.
UUID v7: time first, then randomness
0191f7a8-3c2e-7d5b-9e4f-1a2b3c4d5e6f
│ │
└── 48-bit Unix timestamp (ms)
The layout is:
| Bits | Content |
|---|---|
| 48 | Unix timestamp in milliseconds |
| 4 | Version (7) |
| 12 | Random, or a sub-millisecond counter |
| 2 | Variant |
| 62 | Random |
Because the timestamp occupies the most significant bits, v7 UUIDs sort by creation time when compared as strings or as 128-bit integers. Generate several in a row with the UUID v7 Generator and the first characters march upward.
The 48-bit millisecond field lasts until the year 10889, so overflow is not a practical concern.
Why ordering matters for databases
Most relational databases store primary keys in a B-tree. Inserting a row means finding the right leaf page and writing the key there.
With v4, every new key lands at a random position. Over time this causes:
- Page splits throughout the tree rather than only at the right edge.
- Poor cache locality — recently inserted rows are scattered across the whole index, so the working set is effectively the entire index.
- Fragmentation that inflates index size and slows range scans.
With v7, new keys are always larger than existing ones, so inserts append to the rightmost page — the same access pattern as an auto-increment integer. Benchmarks on PostgreSQL and MySQL routinely show v7 inserts running noticeably faster than v4 at scale, with smaller indexes.
A secondary benefit: ORDER BY id gives you insertion order for free, and you can approximate a created_at range query on the key alone.
What v7 gives away
The timestamp is readable by anyone who sees the ID. From a v7 UUID you can tell roughly when the row was created, and from two of them, which came first. For many systems that is harmless. For some — say, invoice numbers exposed in a URL, where you would rather not leak issuance rate — it is information you did not intend to share.
v4 leaks nothing. If IDs are public and creation time is sensitive, that is a point in v4's favor.
What about v1?
Version 1 was the original time-based UUID. It also embeds a timestamp, but in a scrambled byte order that does not sort naturally, and it includes the generating machine's MAC address. The UUID v1 Generator exists for compatibility with older systems; for new work, v7 does everything v1 did without the drawbacks.
Recommendation
| Situation | Use |
|---|---|
| Primary key in a relational database | v7 |
| Sort or partition by creation time | v7 |
| ID is public and creation time is sensitive | v4 |
| Need an ID with no information content at all | v4 |
| Interoperating with a system that expects v1 | v1 |
For the default case — a primary key that nobody outside the system sees — v7 is the better choice. It keeps the global uniqueness of v4 while restoring the insert locality of a sequence.
Summary
- v4 is 122 random bits with no order; v7 is a 48-bit millisecond timestamp followed by random bits.
- Random keys fragment B-tree indexes; time-ordered keys append, which is faster and smaller.
- v7 reveals creation time. Choose v4 when that matters.
- Both are drop-in replacements for each other at the storage level: same 128 bits, same string format.