Developer
UUID versions explained: random v4, name-based v5, time-ordered v7, and which to pick
A universally unique identifier is a 128-bit value written as 32 hexadecimal digits in five groups. Every UUID looks alike on the page, yet the versions behave very differently: one is pure randomness, one is a hash that always gives the same answer for the same input, and one starts with a timestamp so new values sort after old ones. This article reads the layout digit by digit, explains how each version is built according to RFC 9562, shows real name-based output from this site's generator, and ends with a short guide to choosing one for database keys, file names and public identifiers.
By the MaffeiTools team · Updated · 6 min read
Reading the layout: 128 bits, two fixed fields
The familiar text form is 8, 4, 4, 4 and 12 hexadecimal digits separated by hyphens, 36 characters in total. Case does not matter when comparing, but RFC 9562 asks generators to emit lowercase. Underneath the text there are exactly 16 bytes, and most of them are free for the version to fill as it likes.
Two small fields are fixed. The version is the first hexadecimal digit of the third group, so it can be read at a glance: a 4 there means a random UUID, a 5 means a name-based one, a 7 means a time-ordered one. The variant occupies the top bits of the fourth group. For every UUID produced under the current standard those bits are binary 10, which is why the first digit of the fourth group is always 8, 9, a or b.
Those fixed bits cost six bits of the 128, which is why a random version 4 value carries 122 bits of randomness rather than 128. The two special values are also defined: the nil UUID of all zeros and the max UUID of all f characters, useful as sentinels but never as real identifiers.
- Third group, first digit: the version, from 1 to 8.
- Fourth group, first digit: the variant; 8, 9, a or b for standard UUIDs.
- Everything else: timestamp, random or hash bits depending on the version.
Version 4: randomness and the birthday bound
A version 4 UUID is 122 random bits with the version and variant fields set. Browsers expose this directly through crypto.randomUUID, which draws from the same cryptographically secure generator used for keys. The v4 generator on this site fills the random bits from crypto.getRandomValues, the same secure source. No clock, machine address or counter is involved, so a v4 value reveals nothing about when or where it was made.
Uniqueness is a matter of probability. With 122 random bits, the chance of any collision reaches about one in a billion only after roughly 103 trillion values have been generated. In practice a duplicate v4 UUID almost always points to a broken random source, such as a seeded generator shared between processes, rather than to bad luck.
The weakness of v4 is ordering. Values are spread uniformly, so inserting them as the primary key of a B-tree index writes to random pages. On large tables that means more page splits, poorer cache use and slower inserts than a key that grows over time. For identifiers that are never indexed in insertion order, such as session identifiers or file names, this does not matter.
Version 5: the same name always gives the same UUID
A version 5 UUID is derived rather than generated. The algorithm takes a namespace UUID and a name, concatenates the namespace's 16 bytes with the name's UTF-8 bytes, hashes the result with SHA-1, keeps the first 16 bytes of the digest and then overwrites the version and variant fields. Version 3 is identical but uses MD5, and RFC 9562 recommends 5 over 3 for new work.
The standard predefines namespaces for domain names, URLs, ISO object identifiers and X.500 names, and any UUID can serve as a private namespace. The useful property is repeatability: two systems that never talk to each other will compute the same identifier for the same namespace and name, which makes v5 a good fit for deduplicating imports or giving a stable key to something that already has a unique name.
The example below is real output from the UUID v5 generator on this site. The DNS namespace and the name of this site produce the same value on every run and on every machine. Note the 5 at the start of the third group and the a at the start of the fourth.
namespace (DNS) : 6ba7b810-9dad-11d1-80b4-00c04fd430c8
name : www.maffeitools.com
run 1 : 6333bd52-8408-5836-a83c-bf146c2297a1
run 2 : 6333bd52-8408-5836-a83c-bf146c2297a1
^ ^
version 5 variant (a = binary 10xx)Worth knowing. A v5 UUID is not secret. Anyone who can guess the namespace and the name can compute it, so it must never be used as an access token or an unguessable link.
Version 7: a timestamp in front, randomness behind
Version 7, introduced by RFC 9562 in 2024, places a 48-bit Unix timestamp in milliseconds in the first six bytes and fills most of the remainder with random bits. Because the most significant bits are time, values created later compare greater than values created earlier, both as text and as bytes. That single change fixes the index locality problem of v4 while keeping enough randomness to generate values on many machines without coordination.
The standard also allows a v7 generator to use some of the random bits as a counter or as extra clock precision, so that several values created in the same millisecond still sort in creation order. Implementations differ on this detail, which matters only when strict ordering within one millisecond is required.
The trade-off is disclosure. The first twelve hexadecimal digits of a v7 UUID are the creation time, readable by anyone who sees the value. For internal keys that is harmless and often useful when debugging. For identifiers shown to the public, it can reveal when an account or an order was created.
Choosing a version
The right version follows from two questions: does the identifier need to be repeatable from a name, and will it be used as an index key where insertion order matters. The list below covers the common cases. Versions 1 and 6 exist for compatibility with older systems and embed a timestamp and, traditionally, a node identifier that can leak a machine address; new designs rarely need them.
- Database primary key on a large table: v7, for index locality.
- Public identifier that should reveal nothing: v4.
- Stable identifier for something that already has a unique name: v5 with a private namespace.
- Session identifiers and one-time tokens: neither; use a dedicated random token of at least 128 bits.
- Human-facing references such as order numbers: a shorter code or a readable slug, with the UUID kept internal.
Storage, comparison and common mistakes
Stored as text, a UUID takes 36 bytes plus overhead. Stored in a native uuid column, as PostgreSQL provides, or as 16 raw bytes elsewhere, it takes 16. The native type also compares correctly and rejects malformed input. When the only option is text, store lowercase consistently so equality checks do not depend on case.
The most frequent mistakes are small. Some code validates UUIDs with a pattern that accepts any hexadecimal digits, which lets through strings with an impossible version or variant. A strict check also tests the version digit and the variant digit, not only the shape. Other code treats a v4 value as a secret, which is reasonable for its randomness but fails for v5 and v7, whose bits are partly or wholly predictable. A third mistake is hashing a name with the wrong byte encoding before building a v5 value, which silently produces a different identifier on another system.
Worth knowing. When two systems must agree on v5 identifiers, write down the namespace UUID and the exact normalisation of the name, such as lowercase and trimmed, next to the code that computes them.