What is a UUID and Why Do We Need Them?
A 128-bit UUID gives 2^122 random values, so collisions are practically impossible. Learn the versions, the collision math, and when to pick UUIDs over integers.
If you've spent any time around modern databases or APIs, you've seen them — strings like 550e8400-e29b-41d4-a716-446655440000. Those are UUIDs, and they quietly solve a problem that's harder than it looks: generating identifiers that are guaranteed unique without anyone coordinating with anyone else.
Let's get into what a UUID actually is, why the uniqueness math holds up, the versions you'll bump into, and when to reach for one instead of a plain old auto-incrementing ID.
What a UUID actually is
A UUID is a 128-bit value that's designed to be unique without any central coordination. UUID stands for Universally Unique Identifier. (Microsoft calls it a GUID, for Globally Unique Identifier — same thing, different name.) It's usually written as 32 hexadecimal digits in five hyphen-separated groups:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Two of those positions aren't random. The M digit identifies the version (1, 4, 7, and so on), and the first digit of the N group identifies the variant — almost always 8, 9, a, or b for the standard variant. Everything else depends on the version. The whole layout is pinned down by RFC 9562, the 2024 spec that defines the modern versions and obsoletes the older RFC 4122.
By far the most common version is UUID v4, which is essentially random: 122 of the 128 bits are random, and the remaining 6 are fixed to encode the version and variant.
example v4: 550e8400-e29b-41d4-a716-446655440000
^4 = v4 ^a = RFC 4122 variant
The collision math
Collisions are mathematically negligible — you can stop worrying about them. 122 random bits gives you 5.3 × 10^36 possible values (that's 2^122). It's a genuinely absurd number. The figure people care about, though, comes from the birthday paradox: how many UUIDs can you crank out before two of them colliding becomes even remotely likely?
For UUID v4, the answer is comforting. Generate a billion UUIDs per second, keep it up for 85 years straight, and you'd still face only about a 1 in a billion chance of ever seeing a single collision. To put it another way, you're more likely to be struck by lightning twice in one day than to witness a UUID v4 collision in any realistic workload.
The practical takeaway is simple: treat UUID v4 as guaranteed unique and stop worrying about collisions, even at planet scale.
The versions you'll encounter
There are several UUID versions, each generated by different logic — but in practice you'll only reach for v4 or v7. Here's how they stack up:
| Version | Basis | Time-sortable | Leaks info | Use case |
|---|---|---|---|---|
| v1 | Timestamp + MAC address | Yes | Yes (time + machine) | Legacy; mostly avoided today |
| v3 | MD5 hash of namespace + name | No | No | Deterministic ID from a name |
| v5 | SHA-1 hash of namespace + name | No | No | Deterministic ID from a name (preferred over v3) |
| v4 | 122 random bits | No | No | The safe default; random IDs |
| v7 | Unix-ms timestamp + random | Yes | No | Modern default for new systems |
A bit more context on each:
v1 blends the current timestamp with the generating machine's MAC address. Handy when you want IDs that sort by creation time, but it leaks information — both the creation time and the machine identity — so it's rarely used today.
v3 and v5 are deterministic: hash a namespace UUID together with a name string, and the same input always produces the same output. Useful when you want a stable UUID derived from another identifier, like "the UUID for this URL." v3 uses MD5; v5 uses SHA-1 and is the one to prefer.
v4 is the default modern choice — 122 random bits, no information leakage, no coordination required. This is what you almost always want.
v7, defined in RFC 9562 in 2024, pairs a Unix-millisecond timestamp prefix with random bits. The big win is that it sorts by creation time — which matters a lot for database performance, more on that shortly — without leaking machine identity the way v1 does. It's increasingly the preferred pick for new systems.
You can generate v4 UUIDs with one click using the UUID Generator, and the bulk option spits out up to 100 at once.
Why use UUIDs instead of auto-increment IDs?
Use UUIDs when you need IDs that can be generated anywhere, without a central database handing them out. For decades, the default database primary key was a humble auto-incrementing integer: 1, 2, 3, 4, and on it went. That still works fine for plenty of systems. So why bother with UUIDs at all? Three reasons.
You don't need coordination. With auto-increment, only the database can hand out IDs. With UUIDs, anything can generate one anywhere — your client app, a queue worker, a serverless function — and it's still guaranteed unique. That unlocks a few patterns:
- Offline-first apps can generate the ID before sync and keep it afterward.
- Distributed systems can have multiple services creating records at once with no central coordinator.
- Event sourcing and messaging can stamp each event with a UUID before it's written anywhere.
They don't leak business info. A URL like /api/users/1234 tells anyone watching roughly how many users you have, and that user 1235 probably exists. /api/users/550e8400-e29b-41d4-a716-446655440000 reveals nothing at all. That's why most modern APIs put UUIDs in their URLs.
They merge cleanly across systems. When two systems combine — a company acquisition, or moving data between regions — auto-increment IDs collide all over the place. UUIDs don't.
Why NOT to use UUIDs
Skip UUIDs when you have a single database, a single writer, and no IDs leaking into URLs — integers will be smaller and faster. UUIDs aren't free, and pretending otherwise leads to regret.
Storage. A UUID is 16 bytes (128 bits); an auto-increment 32-bit int is 4 bytes. If your table holds a billion rows across several indexed UUID columns, that adds up to real disk space.
Index performance, especially for v4. Database B-tree indexes are happiest when new rows arrive in roughly sorted order. Random v4 UUIDs blow that up — each new row inserts at some random spot in the index, causing page splits and cache misses. On write-heavy workloads, this measurably reduces throughput: one PostgreSQL benchmark inserting 10 million rows found v7 inserts roughly 35% faster than v4, with a 22% smaller index to boot. RFC 9562 puts the gap even more starkly, noting the real-world difference between time-ordered and random inserts "can be one order of magnitude or more." (This, by the way, is the main reason UUID v7 exists. Its IDs sort by creation time, so they insert at the end of the index like sequential integers, while keeping the no-coordination perks.)
Readability. "User 47291" is a lot easier to say out loud than "user 550e8400-e29b-41d4-a716-446655440000." For internal admin tools, that friction is real. For public URLs it barely matters, since people copy-paste anyway.
URL length. Long UUIDs make for uglier URLs. Some systems lean on shorter encodings — Base62, Crockford Base32, NanoID — purely for cosmetics.
Practical recommendations
Default to v7 for new database primary keys, v4 for general-purpose random IDs, and plain integers when you have a single writer and no distributed concerns. Here's how that breaks down by constraint.
Stick with auto-incrementing integer IDs when you've got a single database with a single writer and no distributed concerns, when IDs never surface in URLs or public APIs, and when you need maximum performance on a write-heavy workload.
Reach for UUID v4 when IDs need to be generated client-side or across distributed systems, when they'll appear in URLs (for anti-enumeration), when multiple data sources will merge down the line, and when the performance hit is acceptable.
Prefer UUID v7 when you have all the reasons for v4 but also want index-friendly time ordering — and when it's available in your database or library. PostgreSQL 18 ships a built-in uuidv7() function (alongside a uuidv4() alias for the older gen_random_uuid()), and recent Node and Python libraries support it too.
And use UUID v5 when you want a deterministic UUID derived from a stable identifier, like a URL or an email address. If you're weighing identifier schemes more broadly, our guides on naming conventions and Base64 encoding cover the adjacent decisions around how identifiers are shaped and transported.
Generating UUIDs
In modern JavaScript it's a one-liner — no library required:
crypto.randomUUID();
// → '550e8400-e29b-41d4-a716-446655440000'
That's the whole thing. crypto.randomUUID() is built into every modern browser (since March 2022) and Node 14.17+. Per MDN, it generates a v4 UUID using a cryptographically secure random number generator, so the values are fine even for security-sensitive contexts. The one catch in the browser: it requires a secure context (HTTPS).
For one-off needs — a test ID, some seed data, a unique filename — the UUID Generator gives you up to 100 fresh UUIDs in your browser with a single click.
The bottom line
A UUID is a 128-bit identifier, usually written as 36 hyphenated hex characters. v4 (random) is the safe default, with collisions that are mathematically negligible, while v7 (time-sortable plus random) is the modern choice for new systems. Use UUIDs when you need no-coordination ID generation, and stick with integers when you need maximum write throughput on a single database. And when you just need one in code, crypto.randomUUID() is built right into the browser — no library needed.
Frequently asked questions
Can two UUIDs ever collide?
In theory yes, in practice no. A v4 UUID has 2^122 random values. You could generate a billion per second for 85 years and still face only about a one-in-a-billion chance of a single collision. Treat them as unique.
UUID v4 vs v7 — which should I use?
Use v4 when you just need a random, no-coordination ID and order does not matter. Use v7 when those IDs become database primary keys, since its time-sortable layout keeps B-tree indexes fast. v7 is the better default for new systems.
Are UUIDs slower than integer IDs?
They can be. UUIDs are 16 bytes versus 4 for a 32-bit int, and random v4 values scatter across a B-tree index. One PostgreSQL benchmark found v7 inserts roughly 35 percent faster than v4 at 10 million rows. Sequential integers remain fastest.
Is crypto.randomUUID() secure?
Yes. Per MDN, it generates a v4 UUID using a cryptographically secure random number generator, so the values are safe for security-sensitive use. It requires a secure context (HTTPS) in the browser and is built into Node 14.17 and later.