v4 (random), v7 (time-ordered), v1, NIL — up to 1000 at once
A UUID (Universally Unique Identifier) is a 128-bit value that creates globally unique identifiers without a central authority. It is standardized in RFC 4122 (classic) and RFC 9562 (v6/7/8). It is represented as 32 hexadecimal digits in five dash-separated groups.
In UUIDv4, 122 of 128 bits are random (the other 6 encode version and variant). The collision probability is astronomically small: even at one billion UUIDs per second for 85 years, the chance of a collision stays below 50%. In practice, UUIDs are treated as collision-free. This tool uses the Web Crypto API (crypto.getRandomValues) for cryptographically strong randomness.
A UUID is 128 bits, traditionally written as 32 hex characters with 4 hyphens — 36 chars total. The fields are time_low (8) - time_mid (4) - time_hi_and_version (4) - clock_seq (4) - node (12). The version lives in the first nibble of group three (position 13), the variant in the first nibble of group four (position 17). A v4 UUID is recognized by a 4 at position 13 and a value in {8, 9, a, b} at position 17.
The 2005 standard RFC 4122 defined classic versions 1-5. RFC 9562 (May 2024) superseded it and introduced v6, v7 and v8 as official standards. Before that, v6 and v7 only existed as industry conventions (e.g. ULID, KSUID, Snowflake). The key innovation is v7: 48 bits of Unix milliseconds as a prefix, then 74 bits of randomness — making UUIDs sortable in generation order, a drastic perf win on B-tree indexes in PostgreSQL or MySQL.
Why not a plain auto-increment integer? UUIDs let you generate IDs client-side (no DB round-trip), prevent enumeration attacks (no /api/order/1234 -> 1235) and remain unique across sharding boundaries or distributed systems. Downsides: 16 bytes instead of 4 or 8 per index entry, worse cache locality for v4 (random inserts scatter across the index), poor human readability. v7 significantly mitigates the index downside.
How many UUIDs must you generate before a collision becomes likely? Using the birthday approximation, the count for a 50% collision probability is roughly:
n ≈ sqrt(2 * 2^B * ln(2))
where B = effective random bits.
Version Random bits 50% collision after
---------+-------------+----------------------
v4 122 ~2.7 * 10^18 UUIDs
v7 74 ~1.6 * 10^11 UUIDs (per millisecond bucket)
v1 < 48 seconds under heavy load
UUIDv4 layout (hex):
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
^ ^
Version Variant (y in {8,9,a,b})
UUIDs are the standard tool whenever an ID lives outside a single database row. Five typical scenarios:
id UUID PRIMARY KEY DEFAULT gen_random_uuid(). For tables over 100 million rows use v7: time ordering keeps the B-tree index compact and speeds up INSERTs by 2-5x compared to v4.Idempotency-Key header on POST requests so a retry after timeout does not double-charge. UUIDv4 is the industry default: the client generates a key like 3f29c3e0-b5c1-4f1a-9d4d-7c5b21a4e2f0, the server caches the response under it for 24 hours.s3://bucket/uploads/8d3a9e7c-...-da12fb.pdf. Prevents collisions and makes public links unguessable (capability URL pattern). For images often combined with a hash for content addressing.X-Request-ID: ...) are typically UUIDv4. Lets you follow a request across 20 microservices.UUIDs are not magic. Three common pitfalls: (1) v4 as primary key on large tables — random insert order destroys B-tree index locality and write-ahead logs. Fix: v7 or ULID. (2) v1 in public systems — the first 60 bits encode a timestamp and parts of the MAC address, creating privacy issues (see the "Cohen UUID" story). (3) v4 for security tokens is fine (122 bits of entropy is enough), but if the UUID library does not use crypto.getRandomValues and falls back to Math.random(), all is lost. Verify before use: does your UUID library provably produce cryptographically secure v4 IDs? Node.js crypto.randomUUID() yes, older polyfills often no.
crypto.randomUUID() safe and fast?crypto.getRandomValues.{8D3A9E7C-1F2B-4A5D-9E0F-DA12FB44A1C2}. You can switch formats via this tool's format option.BINARY(16). VARCHAR(36) costs 36 bytes instead of 16 — 2.25x more storage, 2.25x more I/O, slower index scans. For MySQL UUID_TO_BIN(..., 1) additionally swaps the UUID so the timestamp is at the front (pseudo-v7). With v7 that swap is already native.