UUID v7 Generator
Generate time-ordered UUID v7 for database primary keys
…
Formatteren
Wat is UUID v7?
UUID v7 is een volgende-generatie UUID-formaat gestandaardiseerd in RFC 9562 (mei 2024). Het codeert een 48-bit Unix-millisecondentijdstempel in de meest significante bits, gevolgd door versie- en variantmarkeringen, en vult de resterende bits met cryptografisch veilige willekeurige gegevens.
Omdat het tijdstempel de hoge bits beslaat, sorteren UUID v7-waarden chronologisch — zowel lexicografisch als numeriek. Dit maakt ze een uitstekende keuze voor database primaire sleutels, waar willekeurige UUIDs (v4) B-tree-indexfragmentatie veroorzaken.
Waarom willekeurige UUIDs database-indexen fragmenteren
B-tree-indexen — gebruikt door PostgreSQL, MySQL, SQLite en de meeste andere databases — houden rijen gesorteerd op sleutelwaarde. Wanneer u een nieuwe rij invoegt, moet de database deze op de juiste gesorteerde positie in de index plaatsen.
Met UUID v4 (volledig willekeurig) landt elke nieuwe invoeging op een in wezen willekeurige positie in de indexboom. Dit dwingt de database om interne indexpagina's voortdurend te lezen en te herschrijven, volle pagina's te splitsen en andere halfleeg te laten. Het resultaat is een gefragmenteerde, opgeblazen index die zowel schrijf- als leesbewerkingen vertraagt naarmate de tabel groeit.
UUID v7 bitindeling
UUID v7 is 128 bits breed, verdeeld in zes velden:
| Bits | Veld | Doel |
|---|---|---|
| 48 | unix_ts_ms | 48-bit Unix-tijdstempel in milliseconden — beslaat de volledige hoge helft |
| 4 | ver | Versienummer — altijd 0111 (decimaal 7) |
| 12 | rand_a | 12 bits cryptografisch veilige willekeurige gegevens |
| 2 | var | Variantmarkering — altijd 10 (RFC 4122-variant) |
| 62 | rand_b | 62 bits cryptografisch veilige willekeurige gegevens |
De tijdstempelprecisie is 1 milliseconde. Binnen dezelfde milliseconde worden UUID v7-waarden geordend door hun willekeurige suffix — ze zijn niet gegarandeerd sub-milliseconde monotoon toenemend, maar ze zijn k-sorteerbaar: ID's die dicht bij elkaar in de tijd worden gegenereerd, sorteren dicht bij elkaar in de index.
UUID v7 vs UUID v1
Zowel UUID v1 als UUID v7 bevatten een tijdstempel, maar ze verschillen aanzienlijk in ontwerp:
| Kenmerk | UUID v7 | UUID v1 |
|---|---|---|
| Epoche / Tijdbasis | Unix-epoche (1 jan. 1970) | Gregoriaanse epoche (15 okt. 1582) |
| Tijdprecisie | 1 milliseconde | 100 nanoseconden |
| Sorteerbaar | Ja — k-sorteerbaar by design | Nee — tijdvelden zijn door elkaar in de UUID-indeling |
| Privacy | Geen hostinformatie gelekt | Bevat MAC-adres van genererende host |
| DB-indexprestaties | Uitstekend — sequentiële invoegingen, minimale fragmentatie | Slecht — niet-sequentieel ondanks tijdstempel |
| Standaard | RFC 9562 (2024) | RFC 4122 (2005) |
| Native browserondersteuning | Nog niet (geen crypto.randomUUID v7) | Niet native beschikbaar |
Voor elk nieuw project dat tijdgeordende UUIDs nodig heeft, geef de voorkeur aan UUID v7 boven UUID v1. UUID v1 is een legacy-formaat en lekt hostinformatie.
UUID v7 vs ULID
ULID (Universally Unique Lexicographically Sortable Identifier) lost een soortgelijk probleem op als UUID v7. Hier is een vergelijking:
- Volgt de RFC 9562 UUID-standaard — compatibel met alle UUID-tooling
- Koppeltekens-hexadecimaal formaat — universeel erkend
- Native database UUID-kolomondersteuning
- 128 bits totaal
- Crockford Base32-codering — 26 tekens, iets compacter
- Hoofdletterongevoelig en vermijdt dubbelzinnige tekens (I, L, O, U)
- Op het eerste gezicht meer mensleesbaar
- Vereist een bibliotheek — geen native platformondersteuning
Als u zich al in een UUID-ecosysteem bevindt (PostgreSQL uuid-kolom, REST-API's die UUIDs retourneren), gebruik dan UUID v7. Als u vers begint en de voorkeur geeft aan een meer gebruikersvriendelijke codering, is ULID een redelijk alternatief.
UUID v7 in databases gebruiken
UUID v7 wordt nog niet native gegenereerd door de meeste databases, maar het kan worden opgeslagen in standaard UUID-kolommen en worden gegenereerd in applicatiecode of via extensies:
uuid-kolom. De extensie pg-uuidv7 voegt een server-side functie uuid_generate_v7() toe als u door de database gegenereerde ID's nodig heeft.BINARY(16)- of CHAR(36)-kolom. Genereren in applicatiecode. MySQL 8.0+ heeft geordende UUID-ondersteuning via UUID_TO_BIN(UUID(), 1) voor v1, maar v7 vereist generatie op applicatieniveau.TEXT (36 tekens) of BLOB (16 bytes). Genereren in applicatiecode. Lexicografisch sorteren op TEXT werkt correct omdat UUID v7 een tijdstempelprefix met vaste breedte gebruikt.Codevoorbeelden
UUID v7 is nog niet beschikbaar via crypto.randomUUID(). Gebruik een bibliotheek zoals uuidv7 (npm) totdat native ondersteuning beschikbaar komt:
function generateUuidV7() {
const buf = new Uint8Array(16)
crypto.getRandomValues(buf)
const ms = BigInt(Date.now())
// Embed 48-bit Unix ms timestamp
buf[0] = Number((ms >> 40n) & 0xFFn)
buf[1] = Number((ms >> 32n) & 0xFFn)
buf[2] = Number((ms >> 24n) & 0xFFn)
buf[3] = Number((ms >> 16n) & 0xFFn)
buf[4] = Number((ms >> 8n) & 0xFFn)
buf[5] = Number(ms & 0xFFn)
// Set version 7 (0111xxxx)
buf[6] = (buf[6] & 0x0F) | 0x70
// Set variant (10xxxxxx)
buf[8] = (buf[8] & 0x3F) | 0x80
const hex = [...buf].map(b => b.toString(16).padStart(2, '0')).join('')
return `${hex.slice(0,8)}-${hex.slice(8,12)}-${hex.slice(12,16)}-${hex.slice(16,20)}-${hex.slice(20)}`
}
// Node.js 20+ built-in
// import { randomUUID } from 'node:crypto' // v4 only — no v7 yet in stdlib# pip install uuid7 import uuid_extensions uid = uuid_extensions.uuid7() print(uid) # e.g. 018e2b3d-1a2b-7000-8000-abc123456789 print(uid.time) # Unix ms timestamp embedded in the UUID # Or as a plain string from uuid_extensions import uuid7str print(uuid7str())
-- PostgreSQL 13+ extension-free implementation
CREATE OR REPLACE FUNCTION uuid_generate_v7()
RETURNS uuid
LANGUAGE sql
AS $$
SELECT encode(
set_bit(
set_bit(
overlay(
uuid_send(gen_random_uuid())
PLACING substring(int8send(floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint) FROM 3)
FROM 1 FOR 6
),
52, 1
),
53, 1
),
'hex'
)::uuid;
$$;
-- Usage as a default primary key
CREATE TABLE events (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
payload jsonb,
created_at timestamptz DEFAULT now()
);function extractTimestamp(uuid: string): Date {
const hex = uuid.replace(/-/g, '')
const ms = parseInt(hex.slice(0, 12), 16) // first 48 bits = ms timestamp
return new Date(ms)
}
const uid = '018e2b3d-1a2b-7000-8000-abc123456789'
console.log(extractTimestamp(uid).toISOString())
// → "2024-03-15T10:22:05.259Z"