All posts

UUID Versions Explained: v1 vs v4 (and Where v7 Fits)

July 22, 2026 · DevTools

uuid
guid
identifiers
database
developer-tools

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 4 at 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 / v5name-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.com to 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 typeSortableIndex-friendlyOpaque (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 native UUID type — 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?

NeedPick
General-purpose unique ID, no orderingv4 (the default answer)
Sortable by creation time, modern systemsv7 (or ULID/NanoID)
Deterministic ID derived from a namev5
Legacy/interop requirementv1
Session tokens, password-reset linksDon'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