UUID Version 7: Layout, Generation, and Ordering Limits

    1 July 2024Updated 11 September 2026
    5 min read
    Technical explainer
    uuid
    distributed-systems
    best-practices

    What UUID v7 contains

    UUID v7 was standardized in May 2024. It uses 48 bits for a Unix millisecond timestamp, four version bits, two variant bits, and 74 remaining bits. Those remaining fields can contain randomness, optional sub-millisecond precision, and counters; they are not always 74 independent random bits. See RFC 9562, section 5.7.

    FieldBitsMeaning
    unix_ts_ms48Unix timestamp in milliseconds
    version4Version 7
    rand_a12Random data or permitted precision/counter use
    variant2RFC variant bits
    rand_b62Random data or permitted counter use

    This is still a 16-byte UUID. The UUID v7 generator produces examples, and the UUID decoder extracts the timestamp.

    What sorting does and does not mean

    The timestamp comes first, so comparing standard UUID bytes groups values by their encoded milliseconds. Consistently formatted lowercase text also preserves that order under ordinary binary lexical comparison; database-specific comparison rules should be checked.

    Within one millisecond, order depends on the generator. A counter can preserve ordering within a generator's documented scope, but separate processes do not share that state. Clock adjustments, process restarts, delayed events, and transactions that commit out of order all matter.

    Keep a separate business timestamp when you need event time or ingestion time, and use a database sequence or another explicitly designed ordering mechanism when strict order is required. A decoded timestamp is a field supplied by the generator, not evidence that an event occurred then.

    Python 3.14 and later

    Python 3.14 includes uuid7 in its standard library:

    python
    import uuid
    from datetime import datetime, timezone
    
    identifier = uuid.uuid7()
    assert identifier.version == 7
    assert identifier.variant == uuid.RFC_4122
    
    created = datetime.fromtimestamp(identifier.time / 1000, timezone.utc)
    print(identifier)
    print(created.isoformat())

    Python documents a 42-bit counter for ordering within a millisecond. That is one reason to avoid describing every implementation as 74 random bits. Earlier Python versions do not have this standard-library function. See the Python uuid7 API.

    Node.js with the uuid package

    Install the package:

    bash
    npm install uuid

    Save this as example.mjs and run node example.mjs:

    js
    import { v7, validate, version } from 'uuid';
    
    const identifier = v7();
    if (!validate(identifier) || version(identifier) !== 7) {
      throw new Error('Expected a UUID v7');
    }
    console.log(identifier);

    The package name here is uuid, and its exported function is v7. Other packages can have different APIs. The uuid package documentation also explains how explicitly passing options affects its internal state. Use the ordinary no-options call unless you need those controls and have checked their behavior.

    PostgreSQL 18

    PostgreSQL 18 provides native generation and inspection:

    sql
    WITH sample AS MATERIALIZED (
      SELECT uuidv7() AS id
    )
    SELECT id, uuid_extract_version(id), uuid_extract_timestamp(id)
    FROM sample;

    The materialized expression generates one value so the displayed UUID and extracted fields refer to the same sample. Older PostgreSQL versions can store v7 in a uuid column, but do not necessarily provide these generation functions. See PostgreSQL UUID functions.

    Database benefits need measurement

    Values generated near one another tend to reach nearby positions in a UUID index. That can reduce scattered insert work compared with v4. It does not guarantee faster point reads or eliminate contention. Hash sharding also changes where values are routed, even if the original UUID remains ordered inside a shard.

    Before replacing existing IDs, compare your actual insert, lookup, and range-query workload. The database-performance guide provides a measurement method.

    Privacy and collision assumptions

    Version 7 has no MAC-address field, but it exposes generation time. Do not treat it as anonymous or use its value alone as proof of authorization.

    For a generator using 74 independent random bits, collision analysis can be performed within each timestamp bucket. Counter-based generators have different assumptions and state-management requirements. Do not apply the v4 calculator unchanged to v7 or claim identical collision probabilities simply because both occupy 128 bits.

    ULID is a separate identifier format, not another spelling of UUID v7. If you need that format, use the ULID generator; if you need a standard UUID without an embedded timestamp, consider UUID v4.

    Check your implementation

    Use the UUID examples and test vectors to verify versions, v7 timestamps and canonical byte order. Download the fixed fixtures for repeatable tests; generate fresh identifiers for production records.

    Generate Your Own UUIDs

    Ready to put this knowledge into practice? Try our UUID generators:

    Summary

    Understand UUID v7 timestamps, random and counter fields, working Python and Node.js examples, and the limits of time-based ordering.

    TLDR;

    UUID v7 combines a millisecond timestamp with fields for uniqueness. It can improve index locality, but does not guarantee event order, hide generation time, or always provide 74 random bits.