Every UUID carries a version number in the first digit of its third group. That single hex character tells you what algorithm produced the ID and what, if anything, the bits mean. RFC 9562 defines eight versions plus two special values. Here is what each one is for.
xxxxxxxx-xxxx-Vxxx-xxxx-xxxxxxxxxxxx
^ version digit
Version 1: timestamp and MAC address
The original. A v1 UUID packs a 60 bit timestamp counting 100 nanosecond intervals since 15 October 1582, a 14 bit clock sequence to guard against clock rollbacks, and the 48 bit MAC address of the machine that made it. It was designed to be unique across space and time without any randomness at all.
The problems: it leaks the hardware address of your server, and the timestamp bits are stored in the wrong order for sorting, so v1 UUIDs generated in sequence do not sort in sequence. Most libraries now substitute random bits for the MAC address. v1 still works and is still common in older systems, but there is little reason to pick it for new work.
Version 2: DCE security
A variant of v1 that replaces part of the timestamp with a POSIX user or group ID. It was made for a specific distributed computing environment in the 1990s. Almost nothing generates v2 UUIDs today and many libraries do not implement it. You can safely ignore it.
Version 3 and version 5: name based
These are the only deterministic versions. You give them a namespace UUID and a name, such as a URL or a domain, and they hash the two together. v3 uses MD5 and v5 uses SHA-1. The same input always gives the same UUID, which makes them useful when you need a stable ID for something that already has a natural name but you do not want to store a lookup table.
uuid5(NAMESPACE_URL, "https://mybittools.com")
= 7c1a9d6e-2b4f-5e3a-8f1d-9c8b7a6e5d4c (always the same)
Prefer v5. MD5 is broken as a cryptographic hash, and while that does not matter much for ID generation, there is no reason to choose it when SHA-1 is available everywhere.
Version 4: random
122 random bits. No timestamp, no machine info, no meaning. This is the version most people mean when they say "a UUID". It is trivial to generate, impossible to guess, and supported by every language. Its only real drawback is poor sort order, which we compare in UUID v4 vs v7.
Version 6: v1 reordered
v6 takes the exact same fields as v1 but puts the timestamp bits in big endian order at the front. The result sorts correctly by creation time. It exists mainly so that systems with existing v1 data can migrate to something sortable without changing how the timestamp is computed. If you are starting fresh, skip v6 and go to v7.
Version 7: Unix timestamp plus random
The modern default for database keys. A 48 bit millisecond Unix timestamp followed by 74 random bits. It sorts by creation time, does not leak hardware details, and is simple to implement. PostgreSQL 18, Python 3.14, .NET 9 and the major npm and Go libraries all generate v7 natively.
Version 8: custom
v8 is an escape hatch. The RFC reserves it for vendor specific or experimental layouts. Apart from the version and variant bits, you may fill the other 122 bits however you like. If you want to embed a shard ID, a region code or a different clock resolution, v8 is where that goes. The trade off is that no other system can interpret your layout.
The nil and max UUIDs
Two special values sit outside the version scheme. The nil UUID is all zeros:
00000000-0000-0000-0000-000000000000
The max UUID is all ones, written as all f characters. They are useful as sentinels, for example "no parent" or "the end of a range". Never use the nil UUID as a real ID.
Which should you use?
| Need | Version |
|---|---|
| General purpose, unguessable | v4 |
| Database key, sortable by time | v7 |
| Same input must give same ID | v5 |
| Migrating existing v1 data | v6 |
| Custom bit layout | v8 |
| Legacy compatibility only | v1 |
Our UUID generator produces v1, v4 and v7. Generate one of each and compare the third group to see the version digit change.