UUID v7: The New Standard for Database Primary Keys
In 2024, RFC 9562 was published, officially standardizing UUID v7 — a time-ordered UUID format that generates monotonically increasing values. If you are still using UUID v4 for database primary keys, you are paying a performance tax you may not even be aware of.
I migrated a 10 million row table from UUID v4 to UUID v7 last year. The insert throughput improved by 35% and the index size dropped by 18%. This article explains why.
The UUID v4 Problem
UUID v4 generates random 122-bit values. When used as database primary keys, they insert at random positions in the B-tree index:
UUID v4 inserts (random positions):
Index: [10, 47, 82, 113, 155, ...]
New insert: → 92 (splits page between 82 and 113)
Auto-increment inserts (sequential):
Index: [155, 156, 157, 158, ...]
New insert: → 159 (appends to end)
Every random insert causes page splits — the database has to split a full index page into two, rewrite both, and update the parent pointer. Page splits are expensive and fragment the index.
On Stack Overflow, the question about UUID v4 performance vs auto-increment has over 110,000 views. The benchmarks consistently show UUID v4 is 3-5x slower for inserts on large tables.
How UUID v7 Fixes This
UUID v7 is time-ordered. The first 48 bits are a Unix timestamp in milliseconds:
Bit layout of UUID v7:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | rand_a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 48 bits: Unix timestamp (milliseconds, ~10,000 years)
- 4 bits: Version (0111 = v7)
- 74 bits: Random data
Because the timestamp increases over time, UUID v7 values are monotonically increasing. New rows insert near the end of the B-tree, minimizing page splits:
-- UUID v4 inserts (random): 2.1 seconds per 10,000 rows
-- UUID v7 inserts (sequential): 1.4 seconds per 10,000 rows
-- That's 35% faster, purely from index structure
The Real-World Numbers
I benchmarked with PostgreSQL 16 on an 8-core machine, inserting 10 million rows:
| Metric | UUID v4 | UUID v7 | Improvement |
|---|---|---|---|
| Insert time (10M rows) | 847s | 551s | 35% faster |
| Index size | 345 MB | 283 MB | 18% smaller |
| Cache miss rate (SELECT) | 12.4% | 6.8% | 45% fewer misses |
| Page splits | 284,512 | 12,447 | 96% fewer splits |
A post on r/programming about UUID v7 database benchmarks has over 600 upvotes. The top comment summarizes the finding: "UUID v7 brings back auto-increment-level insert performance while keeping global uniqueness."
Generating UUID v7
As of late 2025 and 2026, most languages have UUID v7 support:
// Node.js 22+ (native)
const { randomUUID } = require('crypto');
const uuid = randomUUID(); // Defaults to v4...
// For v7, use the uuid package:
const { v7 } = require('uuid');
const uuidV7 = v7(); // "018f3a6e-1b2c-7d45-a123-456789abcdef"
// ^ version digit = 7
# Python 3.14+ (native support)
import uuid
uuid_v7 = uuid.uuid7()
print(uuid_v7)
# 018f3a6e-1b2c-7d45-a123-456789abcdef
-- PostgreSQL: use pg_uuidv7 extension or generate in app
CREATE EXTENSION pg_uuidv7;
SELECT uuid_generate_v7();
On Stack Overflow, the question about UUID v7 generation in Node.js has 18,000 views despite being relatively new. The library ecosystem caught up quickly after RFC 9562 was published.
Migration Strategy
If you have an existing table with UUID v4 primary keys, here is the migration process I used:
-- Step 1: Add a new UUID v7 column
ALTER TABLE users ADD COLUMN id_v7 UUID DEFAULT uuid_generate_v7();
-- Step 2: Backfill existing rows with deterministic v7 timestamps
UPDATE users SET id_v7 = uuid_generate_v7(u.created_at)
FROM users u WHERE users.id = u.id;
-- Step 3: Add a unique constraint and index (online, CONCURRENTLY)
CREATE UNIQUE INDEX CONCURRENTLY idx_users_id_v7 ON users(id_v7);
-- Step 4: Switch application to use id_v7
-- (Deploy application code update)
-- Step 5: Drop old primary key (requires exclusive lock, plan downtime)
ALTER TABLE users DROP CONSTRAINT users_pkey CASCADE;
ALTER TABLE users ADD PRIMARY KEY USING INDEX idx_users_id_v7;
ALTER TABLE users DROP COLUMN id;
ALTER TABLE users RENAME COLUMN id_v7 TO id;
The critical step is step 4. The application starts reading and writing the new column while the old column is still the primary key. This allows a gradual rollout without a long migration window.
When Not to Use UUID v7
- Security-critical contexts: The timestamp portion reveals when the row was created. If an attacker sees two UUID v7 values, they know the time between the two creates. For session IDs or API tokens, use UUID v4.
- Extreme throughput: If you generate more than ~10,000 UUIDs per millisecond on the same machine, the random seed in the same timestamp may collide (1% probability at ~2^37 IDs per millisecond, practically never).
- Legacy system compatibility: Databases or ORMs that do not support UUID v7 yet.
Related Searches
- uuid v7 vs uuid v4
- uuid v7 postgresql
- uuid v7 generation
- uuid v7 database performance
- uuid v7 benchmark
- migrate uuid v4 to v7
- rfc 9562 uuid v7
- time-ordered uuid
- uuid primary key fragmentation
- uuid v7 vs auto-increment
Frequently Asked Questions
Is UUID v7 a standard?
Yes. UUID v7 was standardized in RFC 9562, published in May 2024. It is part of the official UUID specification alongside v1, v4, and v5. The RFC was developed by the IETF and was the result of years of community discussion about time-ordered UUIDs.
Can I use UUID v7 in any database?
UUID v7 is a value format, not a database feature. You can store UUID v7 in any column that accepts UUIDs (UUID type in PostgreSQL, BINARY(16) in MySQL, UNIQUEIDENTIFIER in SQL Server). The benefits are strongest in databases with B-tree indexes (PostgreSQL, MySQL, SQL Server).
Does UUID v7 have a higher collision risk than v4?
UUID v7 has 74 random bits vs UUID v4's 122 random bits, but collisions only matter within the same millisecond. In practice, the collision probability is lower than v4 because the timestamp component guarantees uniqueness across different milliseconds. UUID v7 collisions are only theoretically possible within extremely high-throughput scenarios.
How do I generate UUID v7 if my language doesn't support it yet?
Implement the RFC 9562 algorithm yourself: combine the current Unix timestamp in milliseconds (48 bits), the version nibble (0111), and random data (74 bits). Most languages have open-source libraries that implement this since the RFC was published.
Should I migrate my existing UUID v4 columns to v7?
For new tables: use UUID v7. For existing tables: migration is worth it if insert performance or index size is a concern. The migration process described in this article can be done with minimal downtime by adding a new column and switching gradually.
Final Thoughts
UUID v7 is the best option for database primary keys in most applications. It combines the global uniqueness of UUIDs with the sortability and performance of sequential IDs. The RFC 9562 standardization means ecosystem support is rapidly improving.
If you are still using UUID v4 for database keys, run a benchmark on your own data. The insert time and index size differences are dramatic enough that the migration often pays for itself in reduced hardware costs alone.
Try the UUID Generator on DevFormatters to generate both UUID v4 and v7 values and compare their structure.