UUID versions (and when v4 is enough)

Published: 2026-06-26

How RFC 4122 UUIDs encode version and variant bits, what versions 1–5 mean in practice, and why random version 4 IDs are the right default for most applications.

A UUID (Universally Unique Identifier) is a 128-bit value, usually written as 32 hexadecimal digits in five groups separated by hyphens: 8-4-4-4-12. The standard most developers mean is RFC 4122, which defines several versions—different recipes for filling those 128 bits. In modern apps, version 4 (random) is the default choice for primary keys, request IDs, and file names. Understanding the version nibble and variant bits helps you read logs, debug integrations, and know when a different version—or a non-UUID scheme like ULID or NanoID—is a better fit.

UUID layout in one minute

A canonical string looks like:

550e8400-e29b-41d4-a716-446655440000
|------| |---| |---| |---| |----------|
  time   time  ver  clk   node (example labels — meaning depends on version)

Under the hood it is 16 bytes (128 bits). RFC 4122 packs metadata into fixed positions:

Field Position in string Role
Version First hex digit of the third group (…-XXXX-…) Tells you how the UUID was generated (1–5)
Variant First hex digit of the fourth group Must follow the RFC 4122 variant (8, 9, a, or b in that nibble)

For version 4, the version nibble is 4 (for example …-4xxx-…), and the variant nibble is 8, 9, a, or b (for example …-8xxx-…). The remaining bits are random (from a cryptographically secure source in production).

Example v4 (random):

f47ac10b-58cc-4372-a567-0e02b2c3d479
              ^           ^
              version 4   RFC 4122 variant (a = 1010 binary)

Letter case does not change the value. F47AC10B-… and f47ac10b-… are the same UUID. Databases and APIs often normalize to lowercase; comparisons should be case-insensitive.

UUID versions at a glance

RFC 4122 defines five generation algorithms. You can read the version from the string without decoding the rest.

Version How bits are filled Typical use
1 Timestamp + clock sequence + MAC address (or random node if no MAC) Legacy systems; time-ordered if from one host
2 DCE security (like v1 + POSIX UID/GID) Rare today; domain-specific
3 Name-based, MD5 hash of namespace + name Deterministic ID from a fixed name (deprecated hash)
4 Random (122 random bits + version/variant) Default for new IDs
5 Name-based, SHA-1 hash of namespace + name Deterministic ID with a stronger hash than v3

Nil UUID: 00000000-0000-0000-0000-000000000000 — all zeros. It is valid syntax and often means “no id” or a null placeholder in tests and APIs.

Version 1: time + hardware flavor

Version 1 embeds a timestamp and often a network interface identifier. That can be useful when you want rough time ordering without a separate column, but it also leaks when the ID was created and sometimes where (MAC-derived node bits). Many teams avoid v1 for public-facing IDs for privacy and portability reasons.

Versions 3 and 5: same name, same UUID

Given a namespace UUID and a name string, v3/v5 always produce the same UUID. That is ideal for idempotent imports (“user [email protected] in namespace X always gets UUID Y”) but unsuitable when you need unpredictability. Prefer v5 over v3 if you must use name-based UUIDs—MD5 is legacy for new designs.

Version 4: random is the default

Version 4 sets version and variant bits, then fills the rest with random data. Collision risk is negligible at application scale: with proper randomness, birthday-paradox math only becomes relevant at volumes far beyond typical web apps.

When v4 is enough (most cases):

  • Database primary keys and foreign keys
  • Correlation / request IDs in logs and traces
  • Upload filenames and storage keys where sort order does not matter
  • Session or resource tokens where opacity matters more than embeddable metadata

You do not need v1/v3/v5 unless you explicitly want timestamp ordering or deterministic name hashing.

When to consider something other than v4

Need Better option
Sortable by creation time (lexicographic) ULID (timestamp prefix + randomness) or DB created_at + v4
Shorter, URL-friendly IDs NanoID or similar
Deterministic ID from stable name UUID v5 (namespace + name)
Standard interop with existing v1 data UUID v1 (rare for greenfield)
Integer keys for human admin UIs Auto-increment or snowflake-style IDs — not UUIDs

UUIDs are not secrets. A v4 hides no payload, but guessing valid IDs can still be a concern for authorization—use proper access checks, not “obscure UUID.”

Randomness: what “good” looks like

Production v4 UUIDs should use a cryptographically secure random source:

  • Browsers: crypto.randomUUID() or crypto.getRandomValues()
  • Node.js: crypto.randomUUID() / randomUUID from node:crypto
  • Avoid Math.random() for identifiers

The UUID Generator uses crypto.randomUUID() when the browser provides it, otherwise getRandomValues with correct version/variant bit masking—matching RFC 4122 v4 layout.

Validating and storing UUIDs

Common rules:

  • Format: 36 characters with hyphens at fixed positions, or 32 hex digits without hyphens in some databases.
  • Type: Store as UUID/native type when your database supports it; otherwise char(36) with a consistent case convention.
  • Compare case-insensitively unless a broken client forces otherwise.
  • Do not truncate for display in security-sensitive flows (short prefixes collide more often).

Parsing libraries usually accept uppercase and lowercase hex; invalid version/variant combinations should be rejected if you validate strictly.

Common pitfalls

  • Assuming UUIDs are ordered: v4 strings are not time-sorted. Use a timestamp column or ULIDs if sort order matters in indexes or UI.
  • Using v3 for new work: Prefer v5 (SHA-1) for name-based IDs; v3 remains only for legacy compatibility.
  • Treating UUID as secret: IDs are identifiers, not authentication. Pair them with real auth and authorization.
  • Collisions across systems: v4 uniqueness is statistical, not coordinated. Merging datasets rarely collides; if you need global coordination, use a central allocator or deterministic v5 with agreed namespaces.
  • Mixing formats in one column: Pick hyphenated or compact hex consistently in APIs and logs.

Nil UUID in tests and APIs

00000000-0000-0000-0000-000000000000 is the nil UUID. Frameworks use it for “empty” optional IDs, GraphQL nullability patterns, and test fixtures. It is not random—never use it as a production primary key for real entities.

Try it locally in your browser

Use the UUID Generator to:

  • Generate RFC 4122 version 4 UUIDs with Web Crypto randomness.
  • Insert the nil UUID for fixtures and null-id scenarios.
  • Batch up to 500 IDs (one per line) with lowercase or uppercase hex.
  • Copy results in one click—processing stays in your browser; nothing is uploaded.

For sortable identifiers, try the ULID Generator. For shorter custom alphabets, use the NanoID Generator.

Related reading

All learn articles