Random UUIDs solved the problem of generating unique identifiers without coordination, and created a database problem: they insert at random positions, which fragments index and table storage on any system that stores rows in key order.
Version 7 addresses that directly by putting a millisecond timestamp in the high-order bits, followed by randomness. The result is still a UUID, still generatable anywhere, and now roughly sortable by creation time.
What changed in 2026
- Native database support spread. More engines gained built-in generation functions, removing the need for application-side libraries.
- It became the recommended default. Where a UUID is needed, v7 largely displaced v4 in new designs.
- Library support matured. Generation became available across mainstream languages without third-party dependencies in many cases.
- The timestamp exposure got discussed. Awareness that creation time is inferable became part of the decision rather than a surprise.
Why sortability fixes the problem
Databases that store rows in primary key order — or maintain a B-tree index on it, which is nearly all of them — care where a new key lands.
A random key lands anywhere. The target page is usually full, so it splits into two half-full pages. Sustained random insertion produces a structure of half-empty pages: more storage, more pages read per scan, and worse cache utilisation because the same data occupies more space.
A key that increases monotonically always lands at the end. Pages fill completely before a new one is created. No splits, compact storage.
Version 7's timestamp prefix means identifiers generated later sort after identifiers generated earlier, so inserts append. The randomness in the lower bits provides uniqueness within the same millisecond and across generators.
|
v4 (random) |
v7 (time-ordered) |
| Insert position |
Random |
Appends |
| Page splits |
Frequent |
Rare |
| Storage compactness |
Poor |
Good |
| Sortable by creation |
No |
Yes, approximately |
| Reveals creation time |
No |
Yes |
| Uniqueness guarantee |
Random |
Random within a millisecond |
What it reveals
The tradeoff, and it is not hidden: the creation timestamp is recoverable from the identifier.
For most applications that is irrelevant or mildly useful — being able to sort records by identifier and get creation order is convenient.
Where it matters: if the existence and timing of a record is sensitive, publishing an identifier that encodes when it was created discloses that. A record identifier revealing that an account was created at a particular moment may be more than you intended.
It also enables limited inference about volume. Two identifiers created close in time have similar prefixes, so an observer can tell whether records were created together — less informative than sequential integers, and not nothing.
If time must not be inferable, use a fully random version and accept the insert cost, or use an internal integer key with a random external identifier per UUID vs bigint keys.
Practical notes
Store it as a native UUID type, not as text. Text storage roughly doubles the size again and loses type checking. This is a common and entirely avoidable mistake.
Sort order is approximate. Identifiers generated within the same millisecond, or by clocks that are slightly out of sync, may not order strictly by true creation time. Do not use identifier order as an authoritative event sequence — use a timestamp column for that.
Clock behaviour matters. A generator whose clock moves backwards produces identifiers that sort before earlier ones. Rare, and worth knowing if you rely on ordering.
Uniqueness is still probabilistic. Extremely unlikely to collide, and not impossible, so keep the unique constraint.
Common mistakes
- Storing as text. Doubles the size, loses type safety.
- Treating identifier order as authoritative event order. It is approximate.
- Using v7 where creation time must stay private. It is recoverable.
- Assuming it removes the storage overhead. Still 16 bytes.
- Dropping the unique constraint. Probabilistic uniqueness is not a guarantee.
- Mixing versions in one column. Sort order becomes meaningless.
FAQ
Is this the same as ULID?
The idea is the same — a timestamp prefix with randomness. Version 7 is the standardised UUID form, which means native database and library support and compatibility with anything expecting a UUID.
Should I migrate existing v4 identifiers?
Generally not. Migrating primary keys is expensive, and mixed versions in one column defeat the sortability benefit. Use v7 for new tables.
Does it help on databases that do not cluster by primary key?
Less, since rows are not stored in key order. The primary key index still benefits from sequential insertion, so there is a real if smaller gain.
What about the index still being 16 bytes?
Unchanged. Version 7 fixes insert behaviour, not size. If size is your concern, an integer key is the answer.
Where to go next
For the broader key-type decision, read UUID vs bigint keys. For why insert order matters, clustered indexes, and for the fragmentation it prevents, index bloat.