UUID v4: what it is, how random, and when it's a bad idea

What a v4 UUID actually guarantees, why collisions are basically impossible, and the cases where you should reach for v7 or a plain integer instead.

550e8400-e29b-41d4-a716-446655440000 — the most recognizable UUID in existence. You’ve generated thousands of them and never thought about what’s inside. That’s usually fine. But if you’ve ever wondered whether v4 is truly random, whether collisions are real, or whether you should be using it for database primary keys — here’s the honest version.

Anatomy of a UUID

A UUID is a 128-bit number, conventionally written as 32 hex digits in five groups separated by hyphens:

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

Two of those digits encode metadata:

  • M is the version — for v4, always 4.
  • N is the variant — usually 8, 9, a, or b.

So the version nibble is a marker you can read from the string itself. 41d4 in the example above → version 4. That’s how tools and libraries know which UUID strategy generated a value.

How random is v4?

For v4, 122 of the 128 bits are random (the 6 remaining bits are the version and variant markers). The randomness comes from the operating system’s CSPRNG — cryptographic-quality randomness, the same source used for encryption keys.

That means a v4 UUID is not just “random-ish”; it’s cryptographically random. This has a practical consequence: v4 is great for anything where guessability matters — tokens, session identifiers, file names you don’t want enumerated, or any ID you don’t want someone iterating through. It’s the reason UUIDs were created.

Can you get a collision?

Mathematically, yes — it’s possible, and it is also not something you should worry about.

With 122 random bits, generating about 1 billion UUIDs gives you roughly a 1-in-10⁸ chance of a single collision, and you’d need around 2.7 trillion to reach a 50% chance. To outrun that by generation speed alone you’d have to produce over a trillion IDs per second for centuries. In practice: if you get a collision, the RNG is broken, not the math.

When v4 is actually a bad idea

Here’s the part most UUID explainers skip: v4 is the wrong tool for one very common job — database primary keys.

  • Random keys fragment indexes. InnoDB-style clustered indexes store rows in key order. Random keys cause pages to split and rows to land scattered, which hurts insert throughput as tables grow.
  • No ordering. There’s no way to tell which UUID came first, which makes sorting, paging, and time-range queries awkward.
  • 128 bits of overhead on every row, index entry, and foreign key reference, versus 8 bytes for a BIGINT.

The modern answer for DB primary keys is UUIDv7: a time-ordered UUID where the first 48 bits are a millisecond timestamp. It gives you the non-guessable, collision-safe, globally-unique benefits of a UUID and roughly time-sorted inserts that don’t shred the index.

When each is right

  • v4: random identifiers, tokens, anything unguessable — the default when order doesn’t matter.
  • v7: database primary keys and other places where insert order and index health matter.
  • Auto-increment integer: internal, single-database, high-volume tables where global uniqueness across systems isn’t required.

If you just need a batch of random identifiers — test data, file names, seeded fixtures — a UUID v4 generator that produces them locally and in bulk is all you need. Just don’t paste those IDs into your PRIMARY KEY column and wonder why writes get slow at a million rows.