UUID Generation in the Browser: crypto.randomUUID() and the RFC 4122 Standard
UUIDs (Universally Unique Identifiers) are 128-bit labels designed to be unique across space and time without central coordination. They appear everywhere in software — database primary keys, distributed trace IDs, file names, API resources. Since 2021, browsers ship a native method for generating them: crypto.randomUUID().
The RFC 4122 Format
RFC 4122 defines the canonical UUID format as 32 hexadecimal digits in five hyphen-separated groups: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx. The M position encodes the version; the N position encodes the variant (always 8, 9, a, or b for RFC 4122 UUIDs).
// Example v4 UUID
550e8400-e29b-41d4-a716-446655440000
^--- version digit (4)
^--- variant digit (a = 10xx in binary)
UUID Versions: v1, v4, and v7
Version 1 — Time + MAC Address
v1 UUIDs encode the current timestamp (in 100-nanosecond intervals since October 1582) and the MAC address of the generating machine. They are sortable and traceable — but they leak the MAC address and precise generation time. Use v1 only for legacy compatibility.
Version 4 — Random
v4 UUIDs are 122 bits of cryptographically secure randomness (6 bits are reserved for version and variant markers). They have no structure, no time component, no sequential relationship to each other. Collision probability is negligible: the expected number of random v4 UUIDs before a first collision exceeds 2.7 quintillion.
This is what crypto.randomUUID() generates.
Version 7 — Time-Ordered Random
v7 is a newer format from RFC 9562 (the 2024 revision to RFC 4122). It embeds a millisecond-precision Unix timestamp in the most significant bits, followed by random data. The result is lexicographically sortable by creation time while retaining the collision resistance of random UUIDs.
v7 is the right choice for database primary keys: inserting rows with time-ordered UUIDs produces sequential B-tree index writes, avoiding the page fragmentation caused by purely random v4 keys. Relevant for high-write-volume tables in PostgreSQL, MySQL, and SQLite.
crypto.randomUUID() in the Browser
The Crypto.randomUUID() method was added to the Web Crypto API in 2021 and is supported in all modern browsers (Chrome 92+, Firefox 95+, Safari 15.4+, Edge 92+).
// Returns a lowercase hyphenated v4 UUID string
const id = crypto.randomUUID();
// e.g. "550e8400-e29b-41d4-a716-446655440000"
// Also available in:
// - Web Workers and Service Workers
// - Node.js 14.17+ (via globalThis.crypto or require('crypto'))
// - Deno and Bun
Internally it uses the same OS CSPRNG as crypto.getRandomValues(). The spec requires a secure context (HTTPS or localhost).
Generating v7 UUIDs Without Native Support
No browser ships a native crypto.randomUUIDv7() yet. v7 can be constructed from primitives:
function uuidv7(): string {
const bytes = crypto.getRandomValues(new Uint8Array(16));
// Embed Unix timestamp (ms) in the first 48 bits
const ms = BigInt(Date.now());
bytes[0] = Number((ms >> 40n) & 0xffn);
bytes[1] = Number((ms >> 32n) & 0xffn);
bytes[2] = Number((ms >> 24n) & 0xffn);
bytes[3] = Number((ms >> 16n) & 0xffn);
bytes[4] = Number((ms >> 8n) & 0xffn);
bytes[5] = Number(ms & 0xffn);
bytes[6] = (bytes[6] & 0x0f) | 0x70; // version 7
bytes[8] = (bytes[8] & 0x3f) | 0x80; // RFC 4122 variant
return [...bytes]
.map((b, i) => {
const hex = b.toString(16).padStart(2, '0');
return [4, 6, 8, 10].includes(i) ? '-' + hex : hex;
})
.join('');
}
Our UUID generator uses this approach for v7 — timestamp prefix from Date.now(), random suffix from crypto.getRandomValues(), giving monotonic sortability without sacrificing collision resistance.
Choosing a Version
| Use case | Version |
|---|---|
| Database primary keys (sortability matters) | v7 |
| General-purpose unique identifiers | v4 |
| Session tokens, CSRF tokens, API keys | v4 |
| Distributed trace / correlation IDs | v7 |
| Legacy system compatibility | v1 |