UUIDs vs Sequential IDs
By ToolzHive · · 3 min read
When a database needs a unique identifier for every row, there are two broad choices: a counter that goes 1, 2, 3, or a UUID — a 128-bit random-looking value like f47ac10b-58cc-4372-a567-0e02b2c3d479. Each has real strengths, and picking wrongly causes pain later.
What each one is
A sequential ID is an auto-incrementing integer. The database hands out the next number each time you insert a row. Simple, tiny, and naturally ordered.
A UUID (Universally Unique Identifier) is a 128-bit value, usually shown as 32 hex digits in five groups. The common version 4 is almost entirely random. The point is that you can generate one anywhere — on a phone, a server, in the browser — without coordinating with anything else, and it will still be unique in practice.
Why UUIDs exist at all
The killer feature is generation without coordination. With sequential IDs, only the central database can safely issue the next number; two servers guessing independently would collide. With UUIDs, any machine can mint an ID with no round-trip and no lock, and the odds of two colliding are astronomically small. That matters for:
- Distributed systems where many services create records.
- Offline-first apps that generate IDs on the client before syncing.
- Merging data from multiple databases without renumbering everything.
The trade-offs that bite
UUIDs are not free:
- Size. A UUID is 16 bytes versus 4 or 8 for an integer. Across millions of rows and every index that references them, that adds up.
- Index performance. Random UUIDs scatter inserts all over the index, which fragments it and hurts write performance. Sequential IDs append neatly to the end. (Newer "sortable" UUID variants, like v7, fix this by putting a timestamp at the front — worth knowing if you want UUIDs without the write penalty.)
- Human friendliness. "Row 1024" is easy to say, type and eyeball. A UUID is not. Support tickets and debugging are harder.
The security angle people forget
Sequential IDs are guessable and enumerable. If your invoice is at /invoice/1024, an attacker will try /invoice/1025. If the page does not check ownership, that is a data leak — one of the most common web vulnerabilities there is. Sequential IDs also quietly reveal business metrics: a competitor signing up as user 50,000 one month and 55,000 the next has just measured your growth.
UUIDs leak neither. They are not a substitute for proper authorisation checks — you must still verify the user owns the record — but they remove the easy enumeration and the accidental metrics disclosure.
How to choose
A reasonable default:
- Internal primary keys, single database, performance-sensitive → sequential integers. They are smaller and faster, and the guessability does not matter if the ID never leaves the server.
- Public-facing identifiers, distributed generation, or anything an outsider sees in a URL → UUIDs (ideally a sortable variant), to avoid enumeration and coordination problems.
A popular hybrid is to keep a fast integer primary key internally and expose a UUID (or a short random slug) publicly, getting both benefits.
Generating them
Whatever you choose, you will often need throwaway IDs — seeding a test database, mocking an API response, or filling a form field during development. Generating UUIDs on demand, and producing batches of realistic mock records to populate a table, both run in your browser, so you can create as many identifiers and test rows as you need without writing a script or hitting a live service.