A universally unique identifier is 128 bits, written as thirty-two hexadecimal digits in five dash-separated groups. The point is that anything can generate one at any time without coordinating with anything else, and the result will not clash.
That property is what makes distributed systems possible without a central counter — and it is also what made them awkward as database keys, until v7.
The versions worth knowing
v4 — random. 122 random bits, six reserved for version and variant markers. The default nearly everywhere, and the right answer when you want an identifier that reveals nothing.
v7 — time-ordered random. The first 48 bits are a millisecond timestamp; the rest is random. Standardised in 2024 and now the recommended choice for anything that becomes a primary key.
v5 — derived from a name. Hashes a namespace and a string, so the same input always produces the same identifier. Useful for deterministic ids from natural keys, and not random at all.
v1 — timestamp and MAC address. The original. It embeds the generating machine's network address, which is a disclosure nobody intends, and it is worth avoiding for that reason alone.
Why v4 is hard on a database
This is the practical argument and it is not obvious.
A database index is ordered. Inserting a row with an auto-incrementing integer always appends at the end, so the same page stays in memory and writes are cheap.
Random identifiers land everywhere. Each insert touches a different page, the working set becomes the whole index rather than its tail, pages split repeatedly, and the index fragments. On a large table this is the difference between a fast write and a slow one.
v7 restores the ordering. Identifiers generated close together in time sort close together, so inserts cluster at the end again — while keeping the independence that made UUIDs worth having.
Collisions, honestly
122 random bits is about 5.3 × 1036 possibilities. To reach a one-in-a-billion chance of a single collision you need to generate roughly 2.7 × 1018 of them.
At a million per second that is around eighty-five thousand years. The probability is negligible against every other failure mode in the system.
The real risk is not mathematics but a weak random source. A UUID generated from a poorly seeded generator — an embedded device at first boot, a virtual machine cloned from a snapshot — can repeat, and that has happened. The guarantee comes from the randomness, not from the format.
As a secret
A v4 UUID from a cryptographic source is unguessable, and using one as a password-reset link or an unlisted share URL is reasonable.
v1 and v7 are not, and this is worth being clear about. Both embed a timestamp, so anyone who knows roughly when a token was issued has eliminated most of the search space. v1 additionally publishes the MAC address of the machine that made it.
So the version that is best as a database key is the wrong one for a secret. Use v7 for rows and v4 — or a purpose-built random string — for anything that has to be unguessable.
Storing them
As text a UUID is 36 characters. As bytes it is 16, so a native UUID column is worth using where the database has one — less than half the storage, and every index entry smaller.
Where there is no native type, 16 raw bytes beats a 36-character string, at the cost of being unreadable in a query result.
The short version
v4 by default, v7 for anything that becomes a primary key, v5 when the same input must always give the same identifier, and not v1. Collisions are not a real concern; a weak random source is. And a v7 is a poor secret, because half of it is the clock.