← back to blog
databases 7 min read May 2026

UUID v4 vs v7: Which Should You Use as Your Database Primary Key?

UUID v4 has been the default choice for randomly generated primary keys for over a decade. It's universally supported, collision-resistant, and easy to generate. But UUID v7 — standardized in 2024 — introduces monotonic time ordering that significantly reduces index fragmentation in B-tree databases. If you're building a new system today, the choice matters more than most developers realize.

A brief history of UUID versions

The UUID standard (RFC 9562, formerly RFC 4122) defines multiple versions, each with a different generation strategy:

UUID v4: fully random

A UUID v4 looks like this:

f47ac10b-58cc-4372-a567-0e02b2c3d479 ↑ version 4 identifier

122 of the 128 bits are randomly generated (6 bits are reserved for version and variant markers). The probability of two v4 UUIDs colliding is astronomically small — approximately 1 in 5.3 × 10^36 for any single pair. For all practical purposes, v4 UUIDs are unique.

The database performance problem with v4

The problem isn't collision — it's randomness itself. Relational databases store rows in B-tree index structures ordered by the primary key. When a new row is inserted, the database finds the correct position in the B-tree and inserts it there.

With sequential integer IDs (1, 2, 3...), new rows always go at the end of the index. The B-tree's rightmost leaf page grows, which is cache-friendly and requires minimal page splits.

With random v4 UUIDs, new rows are inserted at arbitrary positions throughout the B-tree. This causes:

On a small table, this is imperceptible. On a table with millions of rows receiving hundreds of inserts per second, the performance difference is measurable — sometimes dramatically so.

UUID v7: time-ordered randomness

UUID v7 uses the first 48 bits for a Unix millisecond timestamp, followed by random data:

018f6db5-d840-7c0f-a40e-a8b9c5d3e1f2 └──────────────┘└──────────────────────┘ 48-bit ms 80 bits random + version timestamp

Because the timestamp prefix is monotonically increasing, UUIDs generated later sort after UUIDs generated earlier. New rows are inserted at or near the end of the index — the same locality property as auto-incrementing integers.

The 80-bit random suffix ensures uniqueness even for UUIDs generated within the same millisecond. Multiple systems generating UUIDs simultaneously won't collide because the random portion provides ample collision resistance.

UUID v4

  • 122 bits random
  • No sortability
  • Index fragmentation
  • Universal library support
  • No information leakage
  • Stable, long-established standard

UUID v7

  • 48-bit timestamp prefix
  • Monotonically sortable
  • Sequential index inserts
  • Growing library support
  • Creation time is embedded
  • Standardized in 2024 (RFC 9562)

Security considerations

v7 UUIDs embed a millisecond-precision timestamp. This means:

For most applications, this is a non-issue — you likely already expose creation timestamps through your API. But for use cases where the creation time or ordering of records is sensitive, v4's full randomness is preferable.

Using UUIDs as primary keys: the broader case

Whether you choose v4 or v7, UUID primary keys offer advantages over auto-incrementing integers in several scenarios:

Distributed systems

Auto-incrementing IDs require a central authority to assign the next number. In a distributed system with multiple application nodes, this creates a bottleneck — each node must coordinate with a central ID service. UUIDs can be generated independently on any node with no coordination required.

Security through opacity

Sequential integer IDs expose the total number of records in your system and enable trivial enumeration attacks. If your user IDs are 1, 2, 3... an attacker can iterate through every user. A UUID-based URL like /users/018f6db5-d840-7c0f-a40e-a8b9c5d3e1f2 cannot be guessed or enumerated.

Safe for client-side generation

In some architectures, the client generates the ID before sending the create request. This simplifies optimistic UI updates — the client knows the ID immediately without waiting for a server response. UUIDs are safe for this because the collision probability is negligible.

Which should you use?

For new applications starting today:

PostgreSQL note: PostgreSQL 17 added native support for gen_random_uuid() (v4) and has community extensions for v7. The uuid-ossp extension provides both. MongoDB uses a similar time-ordered ID concept in its ObjectID format, which predates UUID v7.

Migrating from v4 to v7

If you have an existing system with v4 UUIDs and want to switch to v7 for new records:

  1. New records use v7 — existing records keep their v4 UUIDs
  2. Your application should handle both versions transparently (they're the same 128-bit format)
  3. Sorting by primary key will put all old v4 records in a seemingly random order, while new v7 records sort correctly among themselves
  4. If true sort order across all records matters, add a separate created_at timestamp column and sort by that

// summary