UUID Versions Explained: v1 vs v4 (and Where v7 Fits)
July 22, 2026 · DevTools
Every developer eventually needs an ID that's unique without asking anyone — no database sequence, no coordination between services. That's the problem UUIDs (Universally Unique Identifiers) solve: 128 bits of structured randomness that any machine can generate independently.
You can generate v1 and v4 UUIDs right now with the UUID Generator — single or bulk, in several output formats, all in your browser.
Anatomy of a UUID
The familiar form is five dash-separated groups of hex:
550e8400-e29b-41d4-a716-446655440000
└─time_low─┘ └tm┘ └ver┘ └var┘ └─node──┘
Two tiny pieces carry the metadata:
- The version digit (the
4at the start of the third group) tells you how the UUID was made - The variant bits (the
a-ish start of the fourth group) tell you it's a standard RFC layout
Everything else is payload — and what's in that payload depends on the version.
v1: time + machine
A v1 UUID embeds a 60-bit timestamp (100-nanosecond ticks since 1582) and a node identifier, historically the machine's MAC address.
- ✅ Roughly time-ordered — later UUIDs sort later
- ✅ Zero collision risk across machines (different nodes)
- ❌ Leaks when and where it was created — a privacy and fingerprinting concern
- ❌ Same machine, same millisecond, needs a clock sequence to stay unique
v4: pure randomness
A v4 UUID is 122 bits of cryptographically secure randomness with the version and variant bits fixed. Nothing about time or machine — just noise.
- ✅ No information leakage — safe to expose publicly
- ✅ Dead simple, no state, no clock issues
- ❌ Not sortable — random order is rough on clustered database indexes (index fragmentation)
- ❌ Collision risk is nonzero… but see the math below
How unlikely is a v4 collision? With 122 random bits, you'd need to generate about 2.7 × 10¹⁸ UUIDs for a 50% chance of a single duplicate. That's one billion UUIDs per second for ~85 years. For any realistic dataset, "practically impossible" is accurate.
v7: the newcomer (RFC 9562)
Published in 2024, RFC 9562 modernized the spec and formalized v7: a 48-bit Unix millisecond timestamp followed by 74 random bits.
- ✅ Time-ordered like v1 — but with a standard Unix epoch and no MAC address
- ✅ Index-friendly: sequential inserts keep B-trees happy, which is why databases (and tools like Stripe-style IDs) love it
- ✅ Keeps randomness where it matters
If you're starting a new system where sortable IDs matter, look at v7 — or sortable cousins like ULID and NanoID, which the ULID / NanoID Generator can produce.
What about v2, v3, v5 — and the Nil UUID?
- v2 (DCE security) — rare in practice; most libraries skip it
- v3 / v5 — name-based: a namespace UUID plus a name, hashed (MD5 for v3, SHA-1 for v5). The same input always yields the same UUID, which is perfect for deriving stable IDs from natural keys — say, mapping
user@example.comto one canonical ID without a lookup table - Nil UUID — all 128 bits zero (
00000000-0000-0000-0000-000000000000), used as a "no value" sentinel
UUIDs as database keys
The v4-versus-v7 debate matters most at the database layer. Clustered indexes (InnoDB's primary key, for example) store rows in key order. Random v4 inserts land anywhere in the tree, causing page splits and fragmentation that degrade write throughput on large tables. Time-ordered IDs (v7, ULID) append near the end, keeping inserts cheap and indexes compact.
The tradeoffs in short:
| ID type | Sortable | Index-friendly | Opaque (no info leak) |
|---|---|---|---|
| Auto-increment int | ✅ | ✅ | ❌ (leaks record count) |
| UUID v4 | ❌ | ❌ | ✅ |
| UUID v7 / ULID | ✅ | ✅ | ✅ (mostly) |
Generating UUIDs in code
// JavaScript (modern browsers & Node 19+)
crypto.randomUUID() // v4
# Python
import uuid
uuid.uuid4() # v4
uuid.uuid1() # v1
uuid.uuid5(uuid.NAMESPACE_DNS, "example.com") # v5, deterministic
-- PostgreSQL 13+
SELECT gen_random_uuid(); -- v4
Reading a UUID by eye
You can tell a surprising amount from the string alone. Take:
0198c3e2-7b5a-7f3c-9d2e-8a1b4c5d6e7f
^ ^
| └─ variant: 8/9/a/b → RFC 4122 layout
└────── version: 7 → time-ordered
The first 12 hex digits of a v7 are the Unix-millisecond timestamp, so 0198c3e2-7b5a decodes to a real creation date — handy when debugging logs, and a reminder that sortable IDs leak when (though not where) they were made. A v4 like f47ac10b-58cc-4372-a567-0e02b2c3d479 tells you nothing beyond "someone called a random generator".
Migrating from v4 to v7
If you have an existing system on v4, you don't have to migrate anything — old IDs stay valid forever, since the version is self-describing in the string. New rows can simply start using v7 alongside them. The one caveat: don't mix versions inside a single sortable column expecting global order — v4s sort randomly among the time-ordered v7s. Most teams introduce v7 on new tables first, watch the index behavior improve, and never touch the old data.
UUIDs in URLs and APIs
UUIDs shine in public-facing identifiers: /users/550e8400-e29b-41d4-a716-446655440000 reveals nothing about your table size or neighbors, unlike /users/4821. Two practical tips:
- Don't use them for rate-limiting or enumeration-sensitive endpoints alone — opacity is not authorization. Check permissions on every request regardless.
- Case-insensitive matching — users paste IDs from emails and dashboards in mixed case. Normalize to lowercase before lookup, or a valid ID will 404.
Storage and interop notes
- Store as binary, not text. A UUID is 16 bytes; stored as
CHAR(36)it costs more than double the space and slows comparisons. Most databases have a nativeUUIDtype — use it. - Case and braces vary by ecosystem. .NET emits uppercase with braces (
{F47AC...}), Java emits lowercase with hyphens, both parse the same value. Normalize before comparing strings. - JSON has no UUID type, so they travel as strings — validate the format on intake if the ID drives authorization decisions.
Which one should you use?
| Need | Pick |
|---|---|
| General-purpose unique ID, no ordering | v4 (the default answer) |
| Sortable by creation time, modern systems | v7 (or ULID/NanoID) |
| Deterministic ID derived from a name | v5 |
| Legacy/interop requirement | v1 |
| Session tokens, password-reset links | Don't — 122 bits of identifier entropy isn't a secret. Use a purpose-built Token Generator |
A note on GUID vs UUID: they're the same thing. "GUID" is simply Microsoft's name for the RFC 4122 format — 550e8400-... is both.
Formatting and bulk generation
Real workflows need more than one UUID: seeding test databases, generating mock API fixtures, creating batch file names. The UUID Generator covers this — generate up to 100 UUIDs at once, toggle uppercase/lowercase, hyphens on/off, or brace-wrapped (Microsoft style), then copy individually or export as a JSON array, newline-separated text, or SQL INSERT values.
Everything stays in your browser
Generation uses the Web Crypto API locally — no server round-trips, no logs, no chance of your identifiers being observed or reused elsewhere.
Next steps
- Generate some now: UUID Generator
- Need sortable IDs? Try ULID / NanoID Generator
- Building test fixtures? Pair UUIDs with realistic data from the generators in the sidebar