UUID Collisions — Probability Reddit Overstates

(Updated: July 16, 2026 ) webdev uuid databases distributed-systems tools

A thread claims “UUIDs collide all the time; we switched to autoincrement.” Another claims collisions are impossible. Both oversell. At product scale, your generator and your retry logic matter more than the birthday paradox poster math.

What “safety” means in production

Uniqueness is a system property, not a slogan about 122 random bits:

  1. Enough entropy in the ID space
  2. A correct implementation (crypto.randomUUID, DB gen_random_uuid(), and peers)
  3. A uniqueness constraint where duplicates would corrupt data
  4. Idempotent APIs that do not invent new failure modes on retry

Without (3), a theoretical collision is irrelevant — you would not notice. Without (2), constraints fire for mundane reasons that look like “UUID bad” in the ticket title.

Where real duplicate-key tickets come from

CauseSymptomFix
Client retries POST with a new UUID each timeDuplicate business rowsIdempotency keys
Client retries with the same UUIDOne row — good — unless server mishandlesUpsert / conflict handling
Test fixture UUID hardcodedCollision across environmentsGenerate per test
Truncating UUID to a “short id”Actual collisionsDo not truncate primary keys
Predictable PRNG on embedded devicesClusters of repeatsCSPRNG

These dominate over “two random v4s matched.” When ops sees a unique violation, ask which of the rows above happened before you rewrite the schema.

Scale intuition without fake precision

Random 122-bit IDs (UUID v4) make accidental collision probability negligible for counts humans actually store — millions, billions, even aggressive IoT volumes — if the bits are random. You will hit operational limits (storage, index churn, ops complexity) long before the paradox becomes your quarterly risk.

Worry earlier about:

  • Index fragmentation with pure-random primary keys under heavy insert load
  • Log verbosity and URL length
  • Leaking internal counts with serial IDs (the opposite trade-off)
  • Client-side ID generation without idempotency on flaky mobile networks

Generate samples with a UUID tool when documenting APIs or seeding fixtures — never hand-type “random” hex that somehow ships to production.

Design patterns that stay boring

Database primary key — UUID or bigserial both fine; add a unique business key (idempotency_key, external_ref) for the failures you will actually see.

Distributed writers — Prefer UUIDs or Snowflake-style IDs over coordinating a global sequence across regions.

Public resources — UUIDs avoid enumerable /users/1 scraping; still authorize every request. Non-enumerable is not authorization.

v4 versus time-ordered IDs — If insert locality hurts, evaluate UUID v7 or ULID for primary keys while keeping uniqueness guarantees. That is an index performance conversation, not a collision conversation. Do not switch to Math.random string hacks because a meme said UUIDs collide.

Operational checklist

  1. Use OS/crypto UUID APIs — not homemade concatenations.
  2. Enforce UNIQUE at the database for anything that must be unique.
  3. Separate resource id from idempotency key when clients retry.
  4. Never shorten UUIDs for aesthetics in primary keys; use a separate public slug if you need short URLs.
  5. Monitor duplicate-key errors; treat spikes as bugs, not destiny.
  6. Document which version you emit (v4 vs v7) in the API guide so clients stop sorting v4s by time.

Reddit overstates collision drama because collisions make a vivid story. Production uniqueness incidents are almost always prosaic: bad retries, truncated tokens, and test data. Design for those, pick an ID scheme that fits indexes and privacy, and stop debating astronomical probabilities as if they were next quarter’s OKR.