UUID Generator: Versions, Collisions and Choosing an Identifier
Table of Contents
What a UUID Is
A universally unique identifier is a 128 bit value, written as 32 hexadecimal digits in five dash separated groups. Microsoft calls the same thing a GUID; the terms are interchangeable in practice.
The point is generating identifiers without coordination. Any machine can mint one at any time, offline, with no central counter and no risk of clashing with anything produced anywhere else. That property is what makes distributed systems practical.
Two digits carry structure rather than data. The first digit of the third group records the version, and the first digit of the fourth records the variant. Everything else depends on which version you chose.
The Versions and When to Use Them
Version 1 combines a timestamp with the network card address, which makes it sortable but leaks the machine that generated it. That privacy problem is why it fell out of favour.
Versions 3 and 5 are deterministic, hashing a namespace and a name with MD5 or SHA-1. The same input always gives the same identifier, which is useful when you need a stable identifier derived from something you already have.
Version 4 is pure randomness and by far the most widely used. It reveals nothing about when or where it was created.
Version 7 was standardised in 2024 and puts a millisecond timestamp in the leading bits, giving sortable identifiers without exposing hardware. For new systems using UUIDs as primary keys it is generally the better choice.
Version 4 Against Version 7
Version 4 scatters. Successive values land in unrelated places, which is fine as an opaque token and awkward as an index key, because every insert touches a different part of the tree.
Version 7 clusters by time. Rows created together sit together, so inserts append rather than scatter and range queries over creation time become possible directly from the key.
The trade is disclosure. A v7 value reveals when it was created to the millisecond. For an internal row identifier that rarely matters; for a public token it may.
A reasonable rule: v7 for database keys, v4 for anything a user sees or that acts as a secret. Both still carry plenty of randomness.
How Likely Is a Collision
Version 4 has 122 random bits, giving roughly 5.3 times ten to the thirty-sixth possible values. That is about five undecillion.
The birthday problem still applies, but the numbers remain absurd. You would need to generate around a billion UUIDs every second for roughly 85 years before reaching a fifty percent chance of a single duplicate.
The real risk is a bad random source. Every documented UUID collision traces back to weak entropy, such as a virtual machine cloned with identical seed state, rather than to the mathematics. This tool uses the Web Crypto API precisely for that reason.
UUIDs as Database Keys
The advantages are real. Identifiers can be generated by the client before a round trip, merging data from separate systems never conflicts, and row counts are not exposed the way sequential integers expose them.
So are the costs. Sixteen bytes against four or eight for an integer, multiplied across every secondary index. With version 4 the random distribution also causes page splits and poor cache locality on insert.
Store them as binary where you can. PostgreSQL has a native uuid type using 16 bytes; MySQL users should prefer BINARY(16) over CHAR(36), which costs more than twice as much and compares more slowly.
Version 7 removes most of the insert penalty, which is the main reason it exists and why it is worth reaching for in new schemas.
Formatting and Storage
Lowercase with dashes is the canonical form, specified by RFC 9562 and what you should emit. Parsers are expected to accept uppercase on input regardless.
Braces are a Microsoft convention from the COM era, still seen in registry entries and .NET configuration. Strip them before storing.
Dashes carry no information. Removing them saves four characters and is common in URLs and filenames. Just be consistent, because a stored value with dashes will not match one without.
The nil UUID, all zeros, is a valid value meaning explicitly absent. It is useful as a sentinel but should never be a real identifier.
Where UUIDs Are Not Enough
Unguessable is not the same as authorised. A v4 UUID is impractical to guess, which tempts people to treat it as a capability. Anything genuinely sensitive still needs a real authorisation check, because identifiers leak through logs, referrer headers and shared links.
Do not use them as session tokens or API keys. Purpose built tokens carry expiry, scope and revocation. A UUID carries none of that.
Version 1 and version 7 disclose timing. If the moment something was created is sensitive, use version 4.
Never generate them with Math.random. It is not cryptographically secure and is predictable from a handful of outputs. Use the platform crypto API, as this tool does.
Frequently Asked Questions
On using these as secrets: A UUID is hard to guess but carries no expiry, scope or revocation. Protect anything sensitive with a real authorisation check rather than relying on the identifier being unknown.