All articles
Developer August 18, 2026 4 min read

UUID v4 vs v7: Which One to Use as a Database Key

Random UUIDs fragment your index. v7 fixes it by putting a timestamp at the front. Here is the trade-off.

Both are 128-bit identifiers you can generate anywhere without coordinating with a server. The difference is ordering, and it shows up as database performance.

v4: fully random

f47ac10b-58cc-4372-a567-0e02b2c3d479

122 random bits. Collisions are not a practical concern — you'd need to generate billions before the probability becomes worth thinking about.

The problem is insertion order. In a B-tree index, a random key lands in a random page. Every insert touches a different part of the index, so the pages you need are rarely in cache and the tree fragments. On a large, write-heavy table this is measurable.

v7: timestamp first, then random

018f4e2a-7c31-7b3e-8f6d-2a91c4d7e8b0
└─ 48-bit ms timestamp ─┘└── random ──┘

The first 48 bits are a Unix millisecond timestamp. Two consequences:

Sortable. Sorting by ID sorts by creation time. You often get to drop a created_at index entirely.

Sequential inserts. New rows land at the end of the index, like an auto-increment integer. Pages stay hot, the tree doesn't fragment, and bulk inserts get faster.

The trade-off

v7 leaks creation time. Anyone holding the ID can read the millisecond it was generated. That's usually fine, occasionally not — if your IDs are public and the creation time is sensitive, or if the rate of ID creation reveals business volume you'd rather not publish, use v4.

Practical recommendation

  • Primary keys on a table with meaningful write volume → v7
  • Public-facing identifiers where creation time is sensitive → v4
  • Idempotency keys, request IDs, correlation IDs → either; v7 makes logs easier to sort
  • Anything that must not be guessable in sequence → v4

What about auto-increment integers?

Still the fastest option, and still the right call for a single-database application. UUIDs earn their cost when you need IDs generated on the client, offline, or across shards without a coordinator — and when you don't want row counts leaking through sequential IDs.

Storage

Store as uuid in Postgres or BINARY(16) in MySQL — 16 bytes. Storing as VARCHAR(36) costs more than twice the space in the table and in every index that references it. It's a very common and entirely avoidable mistake.

Generating them

SwitchPDF UUID Generator produces v4 and v7 in bulk, using your browser's cryptographic RNG. Useful for seeding test data or grabbing a handful of IDs for a fixture file without wiring up a script.

Bottom line

Default to v7 for anything that becomes a database key — you get free time-sorting and a healthier index. Reach for v4 when the timestamp is something you'd rather not publish.

Related articles