UUID v4 vs v7

v7 for database keys, v4 when the creation time must not show

Use version 7 for database keys and version 4 when the creation time must not show. Both are 128 bits with the same text form and the same 6 bits set aside for version and variant; they differ in what fills the other 122.

The layouts

RFC 9562 defines version 4 (section 5.4) as 122 random bits. Version 7 (section 5.7) starts with 48 bits of Unix milliseconds (t), then the version, 12 bits called rand_a (a), the variant and 62 bits of rand_b (b). V is the digit holding the variant, 8 to b:

v4  rrrrrrrr-rrrr-4rrr-Vrrr-rrrrrrrrrrrr
v7  tttttttt-tttt-7aaa-Vbbb-bbbbbbbbbbbb

The tool’s core, given the same 48 random bytes twice, once for version 4 and once for version 7 with the clock fixed at 2026-10-14T23:54:51.446Z:

v4  ebcdd201-c41e-4139-be9d-3aded876abdf
    b30dc3bf-2f23-4d7d-b459-87077435301a
    715db00a-b1ff-4b8c-ac8b-3508b72a9618
v7  01a13cd7-16b6-7bcd-be9d-3aded876abdf
    01a13cd7-16b6-7bce-b459-87077435301a
    01a13cd7-16b6-7bcf-ac8b-3508b72a9618

The last 16 digits match: version 7 keeps those random bits and puts the time in front. In rand_a the tool writes a counter (bcd, bce, bcf) so a batch from one millisecond still sorts in order. The tool below starts on version 7 with three UUIDs, made from your browser’s bytes and clock instead of these.

Sort order

Version 7 sorts by creation time, as text and as bytes; version 4 sorts at random. In Python 3.14, a thousand of each:

v4 = [uuid.uuid4() for _ in range(1000)]
v7 = [uuid.uuid7() for _ in range(1000)]
print(v4 == sorted(v4), v7 == sorted(v7))
False True

That order makes version 7 the better primary key: new rows go at the right edge of a B-tree index, not on random pages. On PostgreSQL 18, a million uuidv7() keys built a 30 MB index against 38 MB for uuidv4().

Within one millisecond the generator decides: Python 3.14 uses a 42-bit counter, PostgreSQL 18 a sub-millisecond clock fraction, this tool a 12-bit counter. Across machines, the order is only as good as their clocks.

What each gives away

A version 7 UUID tells anyone who sees it when it was made, to the millisecond: paste one into Decode, or use uuid_extract_timestamp() in PostgreSQL 17+ or .time in Python 3.14. A public ID in a URL then dates the account or order behind it. Version 4 shows nothing.

Neither is a secret: RFC 9562 section 8 says not to assume UUIDs are hard to guess, so don’t use either as an access token.

Where to get each

  • JavaScript: crypto.randomUUID() for version 4; the uuid package’s v7() (version 10 and later) for version 7.
  • Python: uuid.uuid4(); uuid.uuid7() from Python 3.14.
  • PostgreSQL: gen_random_uuid() from PostgreSQL 13; uuidv7() from PostgreSQL 18.

A uuid column holds both, so a table can switch its default from version 4 to version 7 without touching old rows.

Try it in the UUID Generator & Decoder

Drawing your browser’s random bytes, 16 per UUID…

Runs in your browser. Nothing you enter is sent anywhere.