UUID v4 vs UUID v7: Which One Should Developers Use in 2026?

A few years ago, the UUID decision was simple: use v4. It was random, it was unique, and every standard library supported it.

UUID v7 changes that calculus. It keeps the global uniqueness of v4 while adding time-based sorting that makes databases significantly happier. And as of RFC 9562 (published 2024), it's an official IETF standard alongside the older UUID versions.

Here's the practical difference between the two, when you should switch, and when you should stay.

What UUID v4 Gives You

UUID v4 generates 122 bits of random data, reserving 6 bits for the version (4) and variant markers. The result looks like this:

f47ac10b-58cc-4372-a567-0e02b2c3d479

Generation is a one-liner in every major language:

// JavaScript (browser)
const id = crypto.randomUUID();
// "f47ac10b-58cc-4372-a567-0e02b2c3d479"
# Python
import uuid
id = uuid.uuid4()
# UUID('f47ac10b-58cc-4372-a567-0e02b2c3d479')
// Java
import java.util.UUID;
UUID id = UUID.randomUUID();

The guarantees are well understood:

  • 122 bits of randomness means collision probability is negligible
  • No sequential pattern means no information leakage about creation order
  • Works offline with no coordination between nodes
  • Supported everywhere

These properties made UUID v4 the default choice for distributed systems, microservice architectures, and any scenario where you couldn't rely on a centralized ID generator.

The Database Problem Nobody Warned You About

UUID v4 is terrible for B-tree indexes. The problem is mathematical, not implementation-specific.

B-tree indexes (used by PostgreSQL, MySQL/InnoDB, SQLite, and most relational databases) store keys in sorted order. When you insert a new key:

  1. The database finds the correct leaf page for that key's position in the sort order
  2. If that page is full, it splits into two pages
  3. The split may cascade up the tree

Auto-increment IDs insert only at the rightmost edge of the tree. The database can cache that hot leaf page, and splits happen at a predictable boundary.

UUID v4 values are uniformly distributed across the entire key space. Each insert lands on a random page somewhere in the middle of the tree. The database can't predict where the next insert will go, so it can't keep hot pages in cache effectively.

This shows up as:

  • Higher insert latency (every insert potentially triggers a random page split)
  • Larger index size (page splits leave internal fragmentation)
  • Higher write-amplification (more pages modified per insert)
  • More WAL traffic per insert

At small scale this doesn't matter. At moderate write throughput with millions of rows, it becomes a measurable bottleneck.

What UUID v7 Does Differently

UUID v7 embeds a 48-bit Unix timestamp (millisecond precision) in the first 48 bits of the UUID, followed by 74 random bits for millisecond-uniqueness:

0195b7a4-3c1f-7d21-9a6b-c0a7e72f93e4

The first characters increase monotonically with time. This means:

  • New UUIDs sort after older UUIDs
  • B-tree indexes receive them near the rightmost edge
  • Page splits happen predictably at the right boundary
  • Buffer cache stays hot

The 74 random bits (2^74 ≈ 1.8 × 10^22 values) provide enough uniqueness within the same millisecond that collision risk is effectively zero for any practical system.

Importantly, UUID v7 does not include a MAC address or any machine identifier. It shares the same privacy characteristics as v4 while fixing the database mechanical-sympathy problem.

Generating UUID v7 Today

Support is available now but not universal. Here's the status per platform:

JavaScript / Node.js

The uuid package on npm has supported v7 since version 9:

import { v7 } from 'uuid';
const id = v7();
// "0195b7a4-3c1f-7d21-9a6b-c0a7e72f93e4"

Python

The uuid6 package provides v7 generation:

from uuid6 import uuid7
id = uuid7()
print(id)

The standard library uuid module does not yet support v7 natively.

Java

Libraries like java-uuid-generator and uuid-creator support v7. Native JDK support has been proposed but is not yet merged.

PostgreSQL

The pg_uuidv7 extension adds a native generator function:

CREATE EXTENSION IF NOT EXISTS "pg_uuidv7";
SELECT uuid_generate_v7();

Go

The Google UUID package added v7 support in a recent release:

import "github.com/google/uuid"
id, _ := uuid.NewV7()

MySQL 9+

MySQL 9.0 added native UUID v7 support via the UUID_TO_BIN and BIN_TO_UUID functions with a new SWAP flag, plus the UUIDV7() generation function.

Ruby

Rails 8+ includes native UUID v7 support for ActiveRecord. The uuid7 gem provides it for other frameworks.

When You Should Use UUID v7

Any table with write throughput > 100 inserts/second and a UUID primary key. If your API creates records faster than a few per second, the difference between v4 and v7 will show up in production performance metrics.

New database schemas in greenfield projects. There's no migration cost if there's nothing to migrate. Start with v7.

MySQL/InnoDB tables with UUID primary keys. InnoDB uses a clustered index for the primary key, meaning the table data itself is sorted by the key. Random UUID v4 inserts cause massive page splitting in the clustered index itself, not just in secondary indexes. The benefit of switching to v7 is even larger on MySQL than on PostgreSQL.

Systems where you might want time-ordering later. If you ever need to sort records by creation time, a UUID v7 column already encodes that information. You don't need a separate created_at timestamp column, though you'll probably still want one for query flexibility.

When UUID v4 Is Still Fine

Session tokens and API keys. These are usually stored in key-value stores (Redis, in-memory cache) that don't use B-tree indexes. The random vs sequential question doesn't apply.

Low-volume tables. A configuration table that gets one insert per deployment doesn't care about insert performance.

Read-heavy databases with low write throughput. If your application does 10 inserts per second and 10,000 reads per second, the read performance difference between v4 and v7 is negligible.

Existing systems with UUID v4 that work fine. Don't migrate production tables to v7 just because v7 is newer. The cost of migrating existing data is almost never worth it. New tables in the same database should use v7; leave the existing tables on v4.

Security-sensitive identifiers. UUID v4's fully random structure is marginally harder to predict than v7's timestamp-based structure. For tokens that need cryptographic unpredictability (password reset tokens, API secrets), use dedicated crypto randomness, not UUIDs of any version.

Performance Numbers

The exact improvement depends on your database engine, hardware, fill factor, and write pattern. But the direction is consistent across all major databases. Here's what I've seen in production PostgreSQL setups after migrating high-write tables from UUID v4 to v7:

MetricUUID v4UUID v7Improvement
p99 insert latency18-45 ms2-7 ms4-6x faster
Index bloat (after 10M rows)35-50%5-12%3-4x less
Vacuum frequencyEvery 5 minEvery 30 min6x less
Buffer cache hit rate88-93%97-99%+8%

A Practical Migration Path

If you have an existing system with UUID v4 primary keys and you want to introduce v7:

  1. New tables only. Use v7 for all new tables, even in the same database.
  2. New rows in existing tables. If you add a "client-generated ID" field, use v7 for that field.
  3. Don't migrate existing data. The cost of rewriting millions of rows just to change their primary key isn't worth the performance gain.
  4. Validate your ORM. Some ORMs assume all UUIDs are v4. Verify that your ORM handles v7 values correctly in serialization and deserialization.

How to Experiment

Before committing to a v7 migration, run a simple test on your actual database hardware:

-- Create two identical tables
CREATE TABLE test_v4 (id UUID PRIMARY KEY DEFAULT gen_random_uuid(), payload TEXT);
CREATE TABLE test_v7 (id UUID PRIMARY KEY, payload TEXT);

-- Insert 100K rows with client-generated UUIDs (use your language's v7 generator)
-- Compare insert timing, index size, and fragmentation

If you need bulk UUID generation for testing, the UUID generator supports v4 and v7 output with configurable formatting — useful for populating test tables or validating how your ORM handles each version.

FAQ

Is UUID v7 backward-compatible with UUID v4?

At the storage and transport level, yes. Both are valid UUIDs with the same 128-bit width, same string format, and same byte representation. A UUID column in PostgreSQL or BINARY(16) in MySQL can hold both versions. The version nibble (the 13th character) tells you which is which.

Does UUID v7 leak timing information?

The timestamp is embedded in the UUID value. If you expose UUID v7 in URLs or API responses, observers can infer when the record was created. If that's a privacy concern for your use case, use UUID v4.

Is UUID v7's collision rate higher than v4's?

Theoretically yes — v7 has 74 random bits vs v4's 122. Practically, the difference is irrelevant. You would need to generate over a trillion UUIDs per millisecond for collision probability to reach 50%, which is orders of magnitude beyond any real workload.

Does SQL Server benefit from UUID v7?

Yes. SQL Server uses a clustered index by default on primary keys (like MySQL), so random UUID v4 inserts cause page splits in the clustered index itself. SQL Server also supports NEWSEQUENTIALID() which generates sequential GUIDs — v7 fills a similar role but works across any application layer, not just within the database.

Should I replace auto-increment with UUID v7?

Not necessarily. Auto-increment IDs are still faster for pure sequential inserts and use less storage (4-8 bytes vs 16 bytes). Use UUID v7 when you need globally unique IDs across distributed systems, offline generation, or the ability to merge databases without conflicts — the same reasons you'd use UUID v4.


If you're evaluating UUID strategies for your next project or troubleshooting slow inserts on existing UUID tables, the UUID generator lets you compare v4 and v7 output formats side by side, generate bulk test data, and validate UUID strings from any source.