Comparison
UUID v4 vs v7: pick v7 for database keys
v4 for opaque tokens. v7 for everything else, especially database keys.
UUIDs are 128-bit identifiers designed to be globally unique across systems without coordination. The original spec (RFC 4122, 2005) defined five versions; v4 (pure random) was the only one most developers used. RFC 9562 (2024) added v7, and v7 should be the new default for almost every use case where v4 was previously chosen.
The headline differences
| Property | v4 | v7 |
|---|---|---|
| Specified | RFC 4122 (2005) | RFC 9562 (2024) |
| Random bits | 122 | 74 |
| Timestamp embedded | No | Yes (48-bit ms since epoch) |
| Sortable by creation time | No (purely random) | Yes (lexicographic = chronological) |
| Collision probability | ~1 in 10³⁶ for any pair | Effectively zero (timestamp + random combined) |
| Database index friendliness | Poor (random insertion churns B-trees) | Excellent (sequential, append-friendly) |
| Browser support | crypto.randomUUID() since 2021 | Manual generation (no native API yet) |
Why v4 hurts databases
Database primary keys typically live in a B-tree index. B-trees perform best when inserts arrive in sorted order: new keys append to the rightmost leaf, no rebalancing needed, the index page stays warm in cache.
Random keys (v4) destroy all of that. Every insert lands in a random page, potentially causing a page split, certainly causing cache misses, and producing free space scattered across the index that never gets compacted. For write-heavy workloads this manifests as:
- 10-100× higher I/O than sequential keys at the same write rate
- Bloated index files (often 2-3× the size they’d be with sorted keys)
- Query slowdowns as cache hit rate degrades
The Postgres-vs-MySQL benchmarks comparing UUID v4 to bigint primary keys consistently show 2-5× write throughput difference on representative workloads. The fix isn’t to abandon UUIDs — it’s to use the kind of UUID that sorts.
What v7 looks like
A v7 UUID:
01950d29-4f6f-7234-bf01-a8b3c0d9e102 └─────timestamp_ms──────┘ └──random──┘
First 48 bits: Unix timestamp in milliseconds (so good until ~10889 AD). Next 4 bits: version (always 7). Next 12 bits: random. Then 2 bits of variant marker + 62 bits of random. Total random: 74 bits — comfortably collision- resistant.
Two v7 UUIDs created in the same millisecond compete on the 74 bits of random; collision probability inside that millisecond is roughly 10⁻²² for a billion-id system. Across milliseconds, the timestamp makes collisions structurally impossible.
When v4 is still the right choice
- Opaque session tokenswhere you don’t want creation order leaked. v7 leaks ~millisecond- resolution creation timestamps in the prefix, which is fine for database keys but bad for privacy-sensitive tokens.
- API keys, access tokens, password reset tokens: opacity matters more than sortability.
- Anonymisation identifiers: where observing the timestamp would help an attacker correlate.
When v7 is clearly better
- Database primary keys.
- Distributed-system IDs (event IDs, order IDs, trace IDs).
- Anywhere you’d benefit from being able to ORDER BY id and get chronological ordering for free.
- Anywhere range queries on creation time would otherwise need a separate index on created_at.
The migration path
New tables: use v7 from the start. Old tables: usually not worth migrating, but if you’re hitting write-throughput ceilings on a UUID-keyed table, switching to v7 is a worthwhile structural change.
Generate either via our UUID generator, which supports both versions.
Related
Published May 15, 2026