UUID v4 vs UUID v7 — The Full Picture
UUIDs are the standard identifier for modern distributed systems. But not all UUIDs are equal. The version matters a lot, especially at database scale.
UUID v4 — Completely Random
UUID v4 generates 122 random bits. It looks like:
f47ac10b-58cc-4372-a567-0e02b2c3d479
^^^^ ← version 4Version 4 is the most widely used. It is statistically unique — the probability of two v4 UUIDs colliding is roughly 1 in 5 × 10^36, which is effectively impossible in practice.
Generate UUID v4 in different languages:
// JavaScript / Node.js
crypto.randomUUID() // Built-in since Node 14.17 and all browsers
// Output: "f47ac10b-58cc-4372-a567-0e02b2c3d479"# Python
import uuid
str(uuid.uuid4())// Go — github.com/google/uuid
import "github.com/google/uuid"
id := uuid.New().String()The Problem with UUID v4 in Databases
UUID v4 is completely random — consecutive inserts have completely unrelated ID values. This causes a serious performance problem with B-tree indexes:
- Row 1 ID:
f47ac10b-...→ index position 15,032 - Row 2 ID:
3b8e9d42-...→ index position 4,891 - Row 3 ID:
c9a7f16e-...→ index position 22,771
The database has to jump to a different part of the B-tree for every insert. This causes random page splits — each insert potentially reads a different disk page into memory, thrashes the buffer pool, and creates fragmented indexes.
At small scale this is invisible. At millions of rows per day, it degrades INSERT throughput by 30–60% and increases index size significantly.
UUID v7 — Time-Sortable
UUID v7 encodes a 48-bit millisecond timestamp in the first 12 hex characters, followed by random bits:
01924b3d-2a0f-7b42-a891-f47ac10b58cc
^^^^^^^^ ^^^^ ^ ← timestamp + version 7Because the timestamp prefix is always increasing, consecutive v7 UUIDs sort naturally by creation time. The database always appends to the end of the B-tree — the same efficient sequential pattern as autoincrement integers.
Generate UUID v7:
// No built-in support yet — use the uuid package
import { v7 as uuidv7 } from 'uuid';
uuidv7() // "01924b3d-2a0f-7b42-a891-f47ac10b58cc"# Python 3.12+
import uuid
str(uuid.uuid7())// Go — github.com/google/uuid (since v1.6.0)
import "github.com/google/uuid"
id := uuid.Must(uuid.NewV7()).String()Performance Comparison
| Metric | UUID v4 | UUID v7 |
|---|---|---|
| Index fragmentation | High | Low |
| INSERT performance | Degrades at scale | Near-sequential |
| Storage overhead | Same | Same |
| Sortable by time | No | Yes |
| Collision resistance | Extremely high | Even higher |
At 1 million inserts/day, the difference is negligible. At 10 million inserts/day, v7 is measurably faster and produces significantly smaller, less fragmented indexes.
When to Use Each
Use UUID v4 when: - You need maximum compatibility (v4 is supported everywhere) - The volume is small (under a few million rows) - You do not need time-based sorting - You are using a system that does not yet support v7
Use UUID v7 when: - Using UUIDs as database primary keys (PostgreSQL, MySQL, MongoDB) - Inserting at high volume - You need records sortable by creation time - Building new systems where you control the ID generation
Database Recommendations
PostgreSQL: UUID v7 + pgcrypto or the uuid-ossp extension. Store as UUID type.
MySQL 8+: UUID v7 stored as BINARY(16) for best performance (avoid VARCHAR(36)).
MongoDB: ObjectId is MongoDB's native time-sortable ID. For external compatibility, UUID v7 as a string works well.
Check Your UUIDs Online
Use JSONKit's UUID Generator to generate UUID v4 and v7 in bulk. The tool uses crypto.randomUUID() for maximum entropy and lets you copy 1–100 UUIDs at once.