Pick Your Cut: A Chef's Guide to GUID Versions
Most developers learn one GUID / UUID version and stop there. They call Guid.NewGuid(), uuid.uuid4() or crypto.randomUUID(), get a random 128-bit value and move on. It works, so the question never comes up.
But the standard gives you eight versions, plus a special nil value. They all use the same 128 bits, just arranged differently. That changes how they sort, what they reveal and where they fit. Picking the right one is less like grabbing a random ingredient and more like choosing the right knife.
Before you pick, it helps to know how to read one. Then we can walk through the versions that matter, from the original RFC 4122 set to the RFC 9562 additions from 2024.
The versions at a glance
The versions group into a few clear buckets:
Time-based: v1, v6 and v7 carry creation order.
Name-based: v3 and v5 hash a namespace plus a name into a repeatable value.
Random: v4 spends almost all its bits on entropy.
Custom: v8 lets you define the layout.
Legacy: v2 is effectively a fossil.
Nil: all zeros, which means “no value”.
| Attribute | v1 | v2 | v3 | v4 | v5 | v6 | v7 | v8 | Nil/Empty |
|---|---|---|---|---|---|---|---|---|---|
| Type | Time + node | DCE security | Name (MD5) | Random | Name (SHA-1) | Reordered time | Time-ordered + random | Custom | All zeros |
| Deterministic | No | No | Yes | No | Yes | No | No | Depends | Yes |
| Sortable | Yes | Partial | No | No | No | Yes | Yes | Depends | N/A |
| Privacy | Leaks MAC | Leaks IDs | MD5 is broken | Safe | SHA-1 weakened | Safe | Safe | Custom | Not unique |
| Standard | RFC 4122 to 9562 | RFC 4122 to 9562 | RFC 4122 to 9562 | RFC 4122 to 9562 | RFC 4122 to 9562 | RFC 9562 (2024) | RFC 9562 (2024) | RFC 9562 (2024) | RFC 4122 to 9562 |
| Typical use | Distributed systems | Legacy DCE systems | Namespace-based IDs | General purpose | Stable API IDs | Database indexing | Modern default | Experimental | Placeholder |
Why v1 and v2 are mostly retired
v1 was the original design. It combines a timestamp with a node identifier, historically the machine’s MAC address. That gives you sortable, coordination-free IDs, but it also puts hardware data into every value you expose. For anything public, that is a privacy risk.
v2 goes further and folds POSIX UID/GID data into the mix for DCE security contexts. It is rarely implemented, effectively deprecated and safe to ignore in new work. If you see one in the wild, treat it as legacy code with a bad smell.
Both are sortable. Both leak host information. RFC 9562 discourages v1 and treats v2 as obsolete.
Why v3 and v5 still matter
v3 and v5 solve a different problem. They hash a namespace and a name into a fixed value. Feed them the same inputs and you get the same GUID every time. That is useful when an identifier must be reproducible across systems without a shared lookup table.
The difference is the hash function. v3 uses MD5, which is broken. v5 uses SHA-1, which is not perfect but is the better choice here. If you need deterministic IDs, reach for v5 and skip v3.
Use this pattern for stable API identifiers, content-addressed records or anything that needs to map the same input to the same ID.
Why v4 is still the default
v4 uses cryptographically secure randomness for almost all of its 128 bits. No timestamp. No host data. No order. That simplicity is why it became the default in most languages and frameworks.
With 122 random bits, collisions stay theoretical at normal scale. v4 carries no metadata, which makes it a solid choice for tokens, public URLs and external identifiers.
What it does not give you is ordering. That is where the newer versions help.
Why v6, v7 and v8 exist
RFC 9562 added v6, v7 and v8 to solve problems v4 was never meant to solve.
v6 is basically v1 with the timestamp bits reordered so it sorts correctly as a plain string. It mainly exists for teams that already use v1 and want better ordering without changing the format.
v7 is the one most teams should look at. It puts a 48-bit Unix millisecond timestamp first, then fills the rest with randomness. The result sorts by creation time, avoids host data and keeps the decentralized generation model of v4.
For database primary keys, that matters. Random v4 keys scatter inserts across a B-tree index and can cause page splits, write amplification and fragmentation. Time-ordered v7 keys cluster near the end of the index and behave much more like an auto-increment integer. You also get rough chronological ordering for free, which often removes the need for a separate created_at column.
v7 is not perfect. It depends on a reasonably accurate system clock, so a skewed or backward-moving clock can produce out-of-order IDs. And because the timestamp is visible, anyone with the value can see when it was created. That is fine for internal keys, but worth thinking about for public ones.
v8 is the escape hatch. The spec leaves the layout up to you, as long as you set the version and variant bits correctly. That makes it powerful, but also easy to misuse. Only use it when you have a clear reason and you control the full design.
The nil value
The nil GUID is all zeros: 00000000-0000-0000-0000-000000000000. It is not a real identifier. It is a sentinel that means “no value”, like null. Generate it never, compare against it often.
How to choose
The decision is simpler than the history suggests:
New database keys, logs, event streams: use v7. The ordering and index locality are real wins.
User-facing identifiers: use v4. A v7 timestamp leaks creation time.
Reproducible IDs from the same input: use v5.
Migrating an existing v1 system that needs ordering: use v6.
A custom layout you fully control: use v8.
Avoid: v1 and v2 for public work, v3 for new work and nil as a real ID.
That is the short version. If you want the full side-by-side breakdown, the complete GUID version comparison on GUIDsGenerator.com covers the security and standards details in one place.
Make it a decision, not a reflex
Same 128 bits, different job. You would not break down a fish with a bread knife, and you should not hand every system the same identifier just because it is familiar.
Pick on purpose. The default is fine until the moment it stops being fine.
If you enjoyed this post, follow me for more content like this!
Thanks for reading.
— Bruno

