Tools · Text · UUID generator · Guides · Why a Random UUID Isn't a Sortable ID (and When That Matters)

Why a Random UUID Isn't a Sortable ID (and When That Matters)

5 min read

Switch a table's primary key from an auto-increment integer to a UUID, and something quietly changes that most teams don't notice until much later: the new rows stop coming back in the order you inserted them, and on a table that's grown large, writes can get noticeably slower too. Nothing is broken. The UUID is doing exactly what a UUID is supposed to do - it's just not the same thing an auto-increment integer was doing.

Sequential integer IDs in order next to random UUIDs with no order at all Left column shows four boxes labeled 1, 2, 3, 4 stacked in a clean ascending line. Right column shows four boxes with short random-looking UUID fragments, scattered at uneven heights with no visible order between them. Auto-increment 1 2 3 4 UUID v4 3f2a-91c0-... 7bd4-0e6a-... a01f-55c2-... c9e8-3b71-...
Same four rows, inserted in the same order. One ID says which came first. The other doesn't.

What a v4 UUID actually guarantees

A version-4 UUID is 128 bits, and 122 of those bits are genuinely random - the remaining 6 are fixed by the RFC 4122 spec itself, to mark the value as a version-4 UUID in the first place. That's an enormous space to draw from, which is exactly why two independently generated UUIDs essentially never collide. What that randomness does not encode is any information about when the value was created relative to any other value. An auto-increment integer tells you "this row came after that one" just by being bigger. A UUID tells you nothing of the kind - it looks the same whether it was generated a millisecond ago or a year ago.

Why this catches people off guard

Most developers' first primary key is an auto-increment integer, and two of its properties get absorbed as "how primary keys work" without ever being stated out loud: they're small, and they sort by creation order for free. Swap in a UUID for "IDs shouldn't be easily guessable or enumerable" reasons - a genuinely good reason - and both of those properties quietly disappear. The database still runs. The bug, if you can call it that, only shows up the first time someone writes ORDER BY id expecting chronological order, or notices the primary key index has gotten unusually large for the row count.

The real mechanical cost: inserting into a random point in an index

A B-tree index - what most relational databases use for a primary key - is built to be efficient when new values keep landing at the end, which is exactly what an ascending auto-increment integer does. A random UUID lands at a random point in that index on every single insert instead, which forces more page splits and rewrites as the table grows. This is a well-documented, general property of B-tree indexes under random insertion, not something specific to any one tool - it's the concrete mechanical reason UUID primary keys have a real reputation for slower writes at scale, and it's worth knowing before you pick a key strategy for a table you expect to grow large, not after.

Where a UUID's lack of order is actually the point

None of this means UUIDs are a bad choice - they solve a real problem auto-increment can't. If two services need to generate IDs independently, without talking to each other or to a shared counter, only a UUID can guarantee they won't collide. That's genuinely valuable for distributed systems, offline-first apps that sync later, or any case where "ask a central authority for the next number" isn't an option. Randomness that carries no ordering information is a feature there, not a limitation - the whole point is that no service needs to coordinate with any other to pick a safe value.

A concrete version of this: a mobile app that lets someone create records while offline, then syncs them to a server whenever a connection comes back. If the app waited for the server to hand out an ID, offline creation wouldn't be possible at all. Generate a UUID on the device the moment the record is created instead, and the ID is already final and permanently unique before the sync even happens - no renumbering, no "which one gets ID 47" conflict when two offline devices sync back at nearly the same time. The same shape applies to a fleet of app servers behind a load balancer, each inserting rows into its own local queue before a batch job merges them: nobody has to phone home for the next number first.

Guessable and out-of-order are two different problems

It's worth separating these, because they get conflated often: an auto-increment ID being sequential means someone can guess that /orders/1042 is probably followed by /orders/1043, which is a real information-leak and enumeration risk in a public URL. A UUID fixes exactly that problem - there's no next value to guess. But "not guessable" and "actually protected" are different things. A UUID in a URL still needs a real authorization check behind it; anyone who obtains a valid UUID (a leaked link, a browser history entry) can still request it if nothing checks whether they're allowed to. Swapping in a UUID closes the guessing attack. It's not a substitute for checking permissions.

Where this tool fits

When you do need a batch of real v4 UUIDs, whether for a database seed, a test fixture, or a spreadsheet column, UUID generator makes them entirely in your browser using the Web Crypto API's random number generator, not Math.random() - the same quality of randomness browsers use for security-sensitive values. Up to 1,000 at once, with format options for case, hyphens and braces. The how-to guide covers the actual steps, and this comparison walks through when to pick a UUID over an auto-increment key for a new table in the first place.

Try UUID generator for free UUID generator

Related tools