DevRivet

Blog ·

Are UUIDs Really Unique? UUID Collision Probability Explained

A random UUID v4 has 122 random bits, so a collision is practically impossible at normal scale. Here is the math, the real risks, and how to avoid them.

UUID Generator

Generate secure UUID v4 and time-ordered UUID v7 identifiers.

Try it free →

For random UUIDs (version 4), the collision probability is so small that you can treat them as unique in practice. A UUID v4 has 122 random bits, so there are about 5.3 × 10^36 possible values. You would need to generate roughly 2.7 × 10^18 of them before the chance of any duplicate reaches 50%. The real risks in production come from bad random number generators, copied state, and truncation, not from the math itself.

If you need a value now, the UUID Generator creates v4 and v7 UUIDs in bulk. The rest of this post explains where the numbers come from and what can actually go wrong.

How many random bits a UUID has

A UUID is 128 bits, written as 32 hex digits in the form 8-4-4-4-12. Some of those bits are fixed by the specification:

  • 4 bits hold the version number. For v4, this is always 4.
  • 2 bits hold the variant. For RFC 4122 UUIDs, the variant bits are always 10 in binary.
  • 122 bits are random in a v4 UUID.

So the space of v4 UUIDs is 2^122, which is about 5.3 × 10^36. The 4 version bits and 2 variant bits are not random, so they do not count toward the space.

The birthday problem and the formula

The question is not whether a new UUID matches one specific existing value. It is whether any two values in a set collide. That is the birthday problem. For n randomly generated values drawn from N possible values, the probability of at least one collision is approximately:

p ≈ 1 - exp(-n^2 / (2N))

For small probabilities, this is close to n^2 / (2N). With N = 2^122, the numbers look like this:

  • 1 million UUIDs (10^6): about 1 in 10^25 chance of any collision.
  • 1 billion UUIDs (10^9): about 1 in 10^19 chance.
  • 1 trillion UUIDs (10^12): about 1 in 10^13 chance, or roughly 1 in 10 trillion.
  • About 2.7 × 10^18 UUIDs: 50% chance of at least one collision.

To put the 1 trillion case in context, a system generating a billion UUIDs per second would need about 17 minutes to reach 10^12 values, and the collision odds would still be tiny. The bottleneck is almost never the number of UUIDs. It is the quality of the generator and how the system uses the values.

Quick check with the formula

You can verify the approximation yourself. In JavaScript:

const N = 2 ** 122;
const n = 1e9;
const p = n * n / (2 * N);
console.log(p.toExponential(2)); // 9.40e-20

In Python, use math.expm1 rather than 1 - math.exp(...). For tiny values, math.exp(-x) rounds to exactly 1.0 in double precision, so subtracting it from 1 gives 0.0:

import math
N = 2 ** 122
n = 10 ** 9
p = -math.expm1(-n * n / (2 * N))
print(f"{p:.2e}")  # 9.40e-20

Both produce the same result, about 9.4 × 10^-20 for one billion v4 UUIDs.

Where UUIDs actually collide in practice

The math assumes each UUID comes from an independent, uniformly random 122-bit value. Real systems break that assumption in several ways.

Weak random number generators

A UUID is only as random as its source. Using a non-cryptographic generator such as Math.random() in JavaScript or a seeded PRNG in another language can produce far fewer effective bits, and duplicates appear much sooner. Use a cryptographically secure source:

// Browsers (secure contexts) and Node.js 14.17+
const id = crypto.randomUUID();
import uuid
id = uuid.uuid4()  # uses os.urandom under the hood

Duplicated state after forking or snapshotting

If a process forks after its random generator has been seeded, or a virtual machine is cloned from a snapshot with the same RNG state, both copies can produce the same sequence of UUIDs. This is a real failure mode, and it does not depend on the size of the space. Modern OS-level sources such as /dev/urandom and getrandom() are much less exposed, but custom PRNGs and some embedded or container setups can still reuse state. If you run replicas from one image, make sure each one seeds from the OS, not from a fixed or copied value.

Truncation and custom formats

Shortening a UUID to fit a field, such as keeping only the first 8 hex digits, reduces the space to 32 bits. At that size, the birthday threshold drops to about 77,000 values for a 50% chance of collision. Keep the full 36-character form, or at least the full 128 bits, when uniqueness matters.

Deterministic UUIDs

Version 5 (SHA-1 with a namespace) and version 3 (MD5 with a namespace) are deterministic by design. The same name and namespace always produce the same UUID. That repeatability is intended, and it is not a random collision. It does mean you should not use v3 or v5 when each record needs its own identity, because identical inputs will always map to the same ID. Also, v3 and v5 hash outputs are not designed for secrecy.

Version 1 and MAC addresses

Version 1 UUIDs combine a timestamp, a clock sequence and a node identifier, which was historically a MAC address. Collisions are avoided if the clock sequence is handled correctly, but v1 leaks timing and host information. If you do not need that ordering or the time component, use v4.

Copy and paste errors and bad joins

Most real duplicate-key bugs are not UUID collisions. They come from a value being generated once and reused, from a seed record inserted twice, or from an ID being assigned in application code and retried without idempotency. If you see a duplicate key error, check the write path before blaming the generator.

v7 UUIDs and time-ordered values

Version 7 UUIDs put a 48-bit Unix millisecond timestamp in the high bits, then use random bits for the rest. That leaves 74 random bits per millisecond, which is still far more than enough to avoid collisions for normal workloads. The main advantage is ordering: v7 values sort roughly by creation time, which helps database indexes. The tradeoff is that the timestamp is visible and the random space is smaller than v4 within the same millisecond. For a detailed comparison, see UUID v4 vs v7: Which Should You Use?.

How to protect against duplicates in your system

  1. Generate IDs with a cryptographically secure source, such as crypto.randomUUID() or uuid.uuid4().
  2. Store UUIDs in a column with a UNIQUE or PRIMARY KEY constraint, so the database enforces uniqueness.
  3. Keep the full 128-bit value. Do not truncate, and store it as a native UUID type where your database supports one.
  4. Make inserts idempotent when retries are possible, for example by using a client-generated ID that is reused on retry.
  5. Ensure forked processes and cloned VMs reseed their random source before generating IDs.

With these in place, the remaining risk is far smaller than many other failures in a typical stack.

FAQ

Can two UUID v4 values ever be the same?

Yes, in theory. The chance is so small that for ordinary applications you can treat v4 UUIDs as unique. Even at a billion values, the probability of any collision is around 10^-19.

Is UUID collision a real concern for databases?

Rarely. A duplicate key error is far more likely to come from a bug that reuses an ID, a retry that inserts twice, or an ID that was truncated or generated with a weak source. A UNIQUE constraint will catch any true duplicate.

Is a UUID safe to use as a secret or token?

Not by itself. Uniqueness is not the same as unpredictability in every context, and UUIDs were not designed as authentication secrets. Use a dedicated token generator with enough entropy and a proper authentication scheme. Tools like the JWT Decoder show what a signed token contains, but they do not replace secure token design. DevRivet tools run in your browser, but you should still avoid pasting live secrets into any web tool.

How many UUIDs before I should worry?

For random v4 values, the 50% threshold is about 2.7 × 10^18. Well before that, the more relevant concerns are generator quality, state duplication and how you store and index the values.

UUID Generator

Generate secure UUID v4 and time-ordered UUID v7 identifiers.

Try it free →