Sitemap

Member-only story

Why We Stopped Using UUIDs as Primary Keys (Even Though Everyone Loves Them)

8 min readJun 14, 2026

--

Index fragmentation, join performance, and a hybrid solution that gave us the best of both worlds.

There’s a certain comfort in reaching for UUIDs. You’ve got a globally unique identifier, no coordination needed between nodes, no risk of ID collision when you merge data across services, and your URLs look pleasantly opaque instead of exposing /users/1, /users/2 to the world.

Press enter or click to view image in full size

We did the same thing. For about two years, every table in our system used uuid as the primary key. It felt like the responsible, production-ready choice.

Then we started noticing something. Write performance was slowly degrading. Bulk inserts that used to take 200ms were creeping toward 800ms. Index sizes were ballooning. A simple join between orders and order_items — tables with fewer than 10 million rows combined — was doing full index scans when it had no business doing so.

We went looking for the culprit, and it kept pointing back to the same thing: UUIDs.

The Real Problem With UUIDs as Primary Keys

Let me be specific. The issue isn’t UUIDs themselves — it’s using random UUIDs as a clustered primary key on a B-tree index, which is what most PostgreSQL and MySQL setups do by default.

--

--