The UUID Landscape Has Changed

If you learned UUIDs from RFC 4122 (2005), you learned UUID v1 through v5. In 2024, RFC 9562 superseded RFC 4122 and standardized v6, v7, and v8. UUID v7 is the standards-based choice to evaluate when a system needs decentralized identifiers with approximate creation-time order. RFC 9562 recommends v7 instead of v1 or v6 when possible; it does not require v7 instead of v4 for every application.

Direct answer: use UUID v4 when you want a random identifier without an embedded timestamp. Evaluate UUID v7 when index locality and time ordering matter, then test clock behavior, concurrency, storage format, and privacy. Neither version guarantees uniqueness or grants authorization; enforce a unique constraint and treat access control separately.

UUID Anatomy

A UUID is a 128-bit value, displayed as 32 hex digits in 8-4-4-4-12 format:

code
550e8400-e29b-41d4-a716-446655440000
         ^^^^
         version nibble (position 13)
              ^
              variant bits (position 17, first 2 bits = 10)

The 128 bits are allocated:

  • 4 bits: version indicator
  • 2 bits: variant indicator (always 10 for RFC 9562)
  • 122 bits: version-specific content

Variant Field

The variant field (bits 64–65 of the UUID) identifies the UUID family:

Variant bits Family
0xx NCS backward compatibility (obsolete)
10x RFC 9562 (formerly RFC 4122)
110 Microsoft COM/DCOM
111 Reserved

All UUIDs discussed here use variant 10x (RFC 9562).

UUID Versions: Complete Reference

UUID v1 — Time + MAC Address

Do not use for new systems.

Encodes a 60-bit Gregorian timestamp (100ns intervals since 1582-10-15) and the 48-bit MAC address of the generating machine.

Problems:

  • Leaks the machine's MAC address (privacy/security)
  • Leaks the creation timestamp (privacy)
  • Timestamp bits are split across non-contiguous fields, preventing lexicographic sorting
  • Requires access to a real MAC address (problematic in containers/VMs)

UUID v4 — Random

122 random bits. No embedded information. The workhorse of the past decade.

code
f47ac10b-58cc-4372-a567-0e02b2c3d479
              ^            variant = 10
              4 = version

Strengths:

  • Simple to generate
  • No privacy concerns
  • No hardware dependencies

Weakness:

  • Not time-ordered — causes B-tree page splits when used as a database primary key

UUID v6 — Reordered Time (v1 Fix)

Takes v1's 60-bit Gregorian timestamp and reorders the bits so that lexicographic sorting equals chronological sorting. Still includes a node field (MAC or random).

Exists primarily as a migration path for systems already using v1 that need sortability.

UUID v7 — Unix Timestamp + Version-Specific Randomness

RFC 9562 §5.7 defines v7 and says implementations should use it instead of v1 or v6 when possible.

Structure:

code
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         unix_ts_ms (48 bits)                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          unix_ts_ms           |  ver  |       rand_a (12)       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|                       rand_b (62 bits)                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           rand_b                                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • 48 bits: Unix timestamp in milliseconds (good until year 10889)
  • 4 bits: version (0111)
  • 12 bits: random data or an optional monotonicity construction (rand_a)
  • 2 bits: variant (10)
  • 62 bits: random (rand_b)

Why teams evaluate v7 for databases:

  1. Time-prefixed layout: canonical byte order groups values approximately by Unix millisecond.
  2. Potentially better B-tree locality: inserts are less scattered than uniformly random v4 values when clocks and generators behave as expected.
  3. Lexicographic chronology: canonical v7 strings sort by timestamp first, while same-millisecond order depends on the generator.
  4. Timestamp visibility: useful for diagnostics, but it leaks creation time and does not replace an authoritative created_at field.
  5. Configurable monotonic behavior: RFC 9562 describes optional methods; strict ordering is an implementation property, not an inherent v7 guarantee.

UUID v8 — Custom/Experimental

Allows implementers to define their own layout within the 122 available bits (after version + variant). Used for domain-specific schemes.

Why Random UUIDs Break B-tree Performance

B-tree indexes (used by PostgreSQL, MySQL InnoDB, SQLite) maintain sorted order. When you insert a random UUID v4 as a primary key:

  1. The new value lands at a random position in the index
  2. The target leaf page is likely not in the buffer pool (cold read)
  3. The page may be full, requiring a page split
  4. Over time, pages are only ~69% full on average (fragmentation)

With UUID v7, timestamp-prefixed values can concentrate recent inserts in a narrower index region. They are not guaranteed to exceed every existing value: clocks can move backward, separate nodes can disagree, and random same-millisecond fields need not be monotonic. Page splits, fill factor, WAL volume, cache behavior, and throughput also depend on database implementation, index settings, row width, concurrency, and workload. Benchmark both schemes on a representative dataset rather than assigning a universal fill factor or speedup.

Collision Probability (Birthday Problem)

UUID v4 has 122 random bits. The birthday problem formula gives the probability of at least one collision after generating n UUIDs:

code
P(collision) ≈ 1 - e^(-n² / (2 × 2^122))
UUIDs generated Collision probability
1 billion (10⁹) ~9.4 × 10⁻²⁰
1 trillion (10¹²) ~9.4 × 10⁻¹⁴
2.71 × 10¹⁸ ~50%
10¹⁸ ~8.98%

For UUID v7, collision analysis depends on how an implementation fills rand_a and rand_b. A fully random layout offers up to 74 random bits within one millisecond; RFC 9562 also permits monotonic methods that trade some random bits for counters or enhanced timestamps. A counter does not by itself eliminate cross-process, cross-node, restart, or clock-rollback conflicts. Follow the library's documented method and retain a unique constraint.

Code Examples

JavaScript / TypeScript

javascript
// Native: crypto.randomUUID() — UUID v4 (all modern runtimes)
const v4 = crypto.randomUUID();

// UUID v7: use a library (uuid@10+)
import { v7 as uuidv7 } from 'uuid';
const id = uuidv7();

// Extract timestamp from v7
function extractTimestamp(uuidV7: string): Date {
  const hex = uuidV7.replace(/-/g, '');
  const ms = parseInt(hex.substring(0, 12), 16);
  return new Date(ms);
}

Python

python
import uuid

# UUID v4 (stdlib)
id_v4 = uuid.uuid4()

# UUID v7 (Python 3.14+)
id_v7 = uuid.uuid7()

# Extract timestamp from v7
def extract_timestamp_v7(u: uuid.UUID) -> float:
    ms = u.int >> 80  # top 48 bits
    return ms / 1000.0

Go

go
package main

import (
    "fmt"
    "github.com/google/uuid"
)

func main() {
    // UUID v4
    v4 := uuid.New()
    fmt.Println(v4)

    // UUID v7
    v7, _ := uuid.NewV7()
    fmt.Println(v7)

    // Extract timestamp from v7
    ts, _ := uuid.TimestampFromV7(v7)
    fmt.Println(ts.Time())
}

PostgreSQL

sql
-- UUID v4 (built-in since PG 13)
CREATE TABLE events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    payload JSONB
);

-- UUID v7 (requires pg_uuidv7 extension or application-generated)
CREATE EXTENSION IF NOT EXISTS pg_uuidv7;
CREATE TABLE events (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
    payload JSONB
);

-- Binary storage: UUID type IS binary (16 bytes) in PostgreSQL
-- No need for BINARY(16) hack — that's MySQL-specific

Storage Formats

Format Size Sortable Indexable Use when
UUID type (PG) 16 bytes Yes (v7) Optimal PostgreSQL
BINARY(16) (MySQL) 16 bytes Yes (v7) Good MySQL InnoDB
CHAR(36) 36 bytes No (random) Poor Never for primary keys
VARCHAR(36) 37 bytes No (random) Poor Display/APIs only
BIGINT 8 bytes Yes Optimal When 64 bits suffice

For MySQL, a v7 value in canonical byte order can be stored as BINARY(16). Do not apply the legacy v1 time-byte swap to v7 without a schema-specific reason:

sql
-- MySQL: store canonical v7 bytes without a v1 byte swap
CREATE TABLE events (
    id BINARY(16) PRIMARY KEY,
    created_at TIMESTAMP(3) GENERATED ALWAYS AS 
        (FROM_UNIXTIME(CONV(HEX(LEFT(id, 6)), 16, 10) / 1000)) STORED
);

Decision Framework: Choosing an ID Scheme

Requirement UUID v4 UUID v7 ULID Snowflake KSUID Auto-increment
Globally unique (no coordination) Yes Yes Yes No (needs worker ID) Yes No
Time-sortable No Yes Yes Yes Yes Yes
B-tree friendly No Yes Yes Yes Yes Yes
Standard (RFC) Yes Yes No No No N/A
Extractable timestamp No Yes Yes Yes Yes No
Privacy (no timing info) Yes No No No No No
128-bit Yes Yes Yes No (64-bit) 160-bit 32/64-bit
Database native type Yes Yes No BIGINT No SERIAL

When to Use What

  • UUID v7: Evaluate for new systems that need standards-based time-prefixed identifiers and can accept timestamp exposure.
  • UUID v4: When you need no timing information to be extractable (privacy requirement), or for backward compatibility.
  • ULID: Similar benefits to UUID v7 but predates RFC 9562. Use if your ecosystem already uses ULID.
  • Snowflake/Twitter IDs: When you need 64-bit IDs (fit in a JavaScript Number) and can tolerate centralized worker ID assignment.
  • Auto-increment: Single-database, no merge/replication, maximum storage efficiency, acceptable security risk (sequential enumeration).

Security Considerations

UUID v1 Leaks Information

UUID v1 embeds the MAC address and exact creation time. Given a v1 UUID, an attacker can:

  • Identify the physical machine that generated it
  • Determine the exact time of creation
  • Correlate UUIDs to track activity patterns

This has led to real privacy incidents in document metadata forensics.

UUID v4 Is Not a Security Token

UUID v4 generated by a CSPRNG has substantial random entropy, but a UUID-shaped value provides no authentication or authorization semantics. If generated with Math.random() or another weak source, it may be predictable. Security tokens need an explicit entropy target, lifecycle, storage, transport, revocation, comparison, and authorization design; do not assume that an identifier's format supplies those properties.

UUID v7 Timestamp Exposure

UUID v7 reveals creation time to millisecond precision. For applications where creation time is sensitive:

  • Use UUID v4 instead
  • Or expose a separate opaque public identifier through a reviewed mapping or token design

Nil and Max UUIDs

RFC 9562 defines two special values:

code
Nil UUID:  00000000-0000-0000-0000-000000000000  (all zeros)
Max UUID:  ffffffff-ffff-ffff-ffff-ffffffffffff  (all ones)

Use Nil as a sentinel for "no value" (similar to NULL but type-safe). Max UUID is useful as an upper bound in range queries.

Try the Formats

The UUID Generator creates RFC 9562 v4 and v7 test values locally and supports bulk output formatting. Use the UUID glossary for a concise version overview. The generator does not replace a database unique constraint or the maintained library used by your application.

Primary Standard

Summary

UUID v7 is the modern RFC option for time-prefixed UUIDs and is preferred by RFC 9562 over v1 or v6 when possible. UUID v4 remains appropriate when a random identifier without extractable creation time fits the requirement.

The case for v7 is workload-dependent: random keys can reduce B-tree locality, while time-prefixed keys may improve it. V7 does not remove clock, concurrency, collision, privacy, or authorization concerns.

Choose your ID scheme based on: coordination requirements, sort order needs, storage budget, privacy constraints, and ecosystem compatibility.