UUID v4 vs UUID v7: Which to Use and When
Abhay Khant
Jan 1, 1970 • 5 min read
UUID v4 vs UUID v7: Which to Use and When
- v4 is 122 bits of pure randomness; v7 leads with a millisecond timestamp
- v7 values sort in creation order, which databases reward with healthier indexes
- Both are collision-safe at any realistic scale under the same RFC umbrella
- v7 leaks creation time by design; v4 leaks nothing but order
What the version number encodes
Every UUID carries its own type in a few reserved bits, so software can tell versions apart on sight. Version 4 fills nearly the entire identifier with random bits, while version 7 spends the first 48 bits on a Unix millisecond timestamp and keeps the rest random. Both come from [RFC 9562](https://datatracker.ietf.org/doc/html/rfc9562), the current specification that replaced [the older RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122) and formally added v6, v7, and v8 alongside the classic versions.
The layout difference is visible in real samples. Here is a v4 generated during research for this guide: 5859c643-66b8-412e-8a3b-7c993f5c14d5. And here is a v7 from the same minute: 01a02617-5ec9-7065-bef5-9098a7907591. The v7 opens with 01a02617 because that hex prefix is the timestamp speaking.
You can read the clock out of a v7
Those leading bits are genuinely decodable. Taking our sample v7 and reading its first six bytes as a big-endian integer yields 1787345460937: milliseconds since the Unix epoch, which is exactly August 21, 2026 at 20:51:00.937 UTC, matching the wall clock when we generated it. No lookup service, no metadata sidecar; the creation moment rides inside the identifier itself.
That property cuts both ways. Debugging gains a free timeline, since support engineers can order events or spot suspiciously old tokens without touching a database. Privacy analysis loses a little, because publishing v7 identifiers discloses when each row came into existence. Systems exposing IDs in public URLs should decide deliberately whether that disclosure is acceptable.
The sort-order difference, measured
We put the headline claim to a direct test using Python's standard library, which ships both generators as of version 3.14 per [its uuid documentation](https://docs.python.org/3/library/uuid.html). Generating five thousand sequential v7 identifiers produced a list already in ascending lexicographic order, exactly as the timestamp prefix predicts. Five thousand sequential v4 identifiers were, predictably, scattered: string order carried no relationship to generation order.
This single property drives most of the practical debate between the two versions. Lexicographic order equals time order for v7, and databases store UUIDs as fixed-size byte strings, so index keys arrive pre-sorted.
Why databases care about ordering
A B-tree index prefers keys that arrive roughly in ascending order because new values append near the right edge of the tree. Fully random keys such as v4 land anywhere, forcing page splits across the whole structure and leaving pages sparsely filled; the effect on large tables is widely documented in database circles, and [PostgreSQL's uuid type documentation](https://www.postgresql.org/docs/current/datatype-uuid.html) notes that ordered variants exist precisely to improve locality for indexing. Teams migrating high-write tables from v4 to v7 typically report calmer write amplification, though the exact benefit varies with workload, fill factor, and storage engine, so measure on your own schema before promising numbers.
Collision odds compared honestly
Version 7 spends 48 bits on the clock, leaving fewer random bits than v4: roughly 74 against 122. Does that hurt uniqueness? The [UUID overview on Wikipedia](https://en.wikipedia.org/wiki/Universally_unique_identifier) walks through the standard birthday-bound arithmetic, and the short answer is no at human scales. Even within a single millisecond window, v7 offers billions of distinct values before collisions become calculable, and cross-millisecond duplicates remain astronomically unlikely. Well-built libraries also guard the same-millisecond case with the monotonicity counters that [RFC 9562 recommends](https://datatracker.ietf.org/doc/html/rfc9562), and our five-thousand-value run never repeated a value.
Choosing between them
| Situation | Better fit |
|---|---|
| New database primary keys, especially high-write | v7 |
| Public-facing identifiers where timing is sensitive | v4 |
| Legacy systems whose parsers expect v4 only | v4 until tooling catches up |
| Event logs needing chronological traceability | v7 |
| Client-side generation in browsers | Either, via crypto.randomUUID or a library |
Browsers make either easy to obtain natively: the [crypto.randomUUID method documented on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) returns a v4, while server runtimes gained v7 support through their standard libraries and popular packages; [Node's crypto module docs](https://nodejs.org/api/crypto.html) show the modern API surface.
Generating and checking UUIDs daily
- Create bulk samples in either version with the UUID generator
- Validate format, version, and variant bits with the UUID validator before wiring an ID into fixtures
- Decode a v7's embedded timestamp when you need to know when an identifier was born
- Keep one version per column; mixing versions inside an indexed column muddies the locality story
The pragmatic read
UUID v4 vs v7 resolves into two honest sentences. For brand-new systems writing serious rows, v7's sortable timestamps buy index health and free chronology, at the price of leaking creation time. For anything privacy-sensitive, legacy-constrained, or simply working fine today, v4 remains the battle-tested default with more randomness per identifier. Measure your own indexes if writes are heavy, and let the decision be boring.


