Most developers pick v4 by default because it's what they've always seen. It's random and fine — until you need sortable IDs, or you're inserting millions of rows into an index.
UUID version 4 is the identifier equivalent of a default font. It's everywhere, it's fine, and almost nobody chose it on purpose — it's just what the tutorial used. For a lot of code, fine is genuinely enough. But "fine" hides real costs in three situations: when you need IDs that sort by creation time, when you're debugging which machine produced an ID, and when you're jamming millions of them into a database index. The version you pick actually matters, and the 2024 update to the spec gave us a better default worth knowing about.
The versions, cleanly
There are several, and you can hold them in your head with one line each:
- v1 — timestamp plus the machine's MAC address.
- v3 — an MD5 hash of a namespace and a name (deterministic).
- v4 — random. The default you've seen a thousand times.
- v5 — a SHA-1 hash of a namespace and a name (deterministic, the better-hashed sibling of v3).
- v7 — a Unix-epoch timestamp plus random bits. Time-sortable and modern.
These were formalised most recently in RFC 9562, which replaced the original 2005 spec and standardised the newer time-ordered versions:
"A UUID is 128 bits long and is intended to guarantee uniqueness across space and time."
— IETF RFC 9562, "Universally Unique IDentifiers (UUIDs)"
Why v4 hurts databases at scale
Here's the failure mode that surprises people. Database primary keys usually live in a B-tree index, which stays efficient when new keys arrive in roughly increasing order — each insert lands near the last one. A v4 UUID is fully random, so every insert lands at a random spot in the index. On a small table nobody notices. On a table with tens of millions of rows, that randomness causes far more page splits and index fragmentation than sequential keys, and both write throughput and index size suffer for it. Teams hit this, blame the ORM or the disk, and never suspect the ID format that was "just the default."
v7: the right default for new projects
UUID v7 fixes exactly that problem. It puts a millisecond timestamp in the high bits and randomness in the low bits, so new IDs are naturally time-ordered while still being practically impossible to guess or collide. That means near-sequential index inserts — the database-friendly property — without exposing a MAC address or a predictable counter. For a new project generating IDs today, v7 is the sensible default and a near drop-in replacement for v4 in most code. You get sortability and index locality for free, and you give up nothing that mattered.
v1 and the privacy problem
v1 embeds the generating machine's MAC address directly in the ID. That's not a hypothetical leak — every v1 UUID a machine produces is traceable back to that specific network card, which is why v1 fell out of favour for anything client-generated or externally visible. If you see v1 in a system that hands IDs to the outside world, treat it as a small information disclosure and move to v7. You can inspect the embedded timestamp of a time-based UUID with a timestamp converter to see exactly what a v1 or v7 value is telling the world about when — and, for v1, where — it was made.
v3 and v5: when you want the same ID every time
Randomness isn't always what you want. v3 and v5 are deterministic: feed the same namespace and the same name, and you always get the same UUID back. That's perfect for stable IDs of canonical things — a URL, a product slug, a well-known entity — where two systems need to agree on an identifier without coordinating. Prefer v5 over v3, because v5 uses SHA-1 rather than the weaker MD5. The mechanics are just hashing under the hood; you can watch a namespace-plus-name turn into a stable digest with a hash generator to build intuition for why the output is reproducible.
The short version
New project, general-purpose IDs: use v7. Need the same ID derived from the same input every time: v5. Debugging or generating one-off IDs by hand: any UUID generator will do, and it's worth generating a few of each version to see the structure — the timestamp prefix on v7, the pure randomness of v4. The one habit to break is reaching for v4 reflexively on a table you expect to grow. It won't break anything today. It'll just quietly cost you at a million rows, and by then it's load-bearing.
← All articles