What UUID v7 is
UUID version 7 is defined in RFC 9562 (2024), which replaced RFC 4122. It puts a 48-bit Unix timestamp in milliseconds at the front, then the version, then random bits. Because the time comes first, v7 UUIDs sort in creation order, as numbers, as bytes and as text, while the rest of the value stays random enough to be unique.
| Field | Bits | Content |
|---|---|---|
| unix_ts_ms | 48 | Milliseconds since 1 January 1970 UTC |
| ver | 4 | 0111 (7) |
| rand_a | 12 | Random, or a counter to keep order inside one millisecond |
| var | 2 | 10 |
| rand_b | 62 | Random |
Read the time from a UUID v7
The first 12 hex digits are the timestamp. In the example value from RFC 9562, 017F22E2-79B0-7CC3-98C4-DC0C0C07398F, the digits 017F22E279B0 are 1,645,557,742,000 in decimal. That is 1,645,557,742 seconds after the epoch, or 2022-02-22 19:22:22 UTC. Paste any v7 UUID in the UUID validator to see its time. The table under the generator above does this for the UUIDs you make, and you can turn timestamps into dates on the Unix timestamp converter.
Why v7 is better than v4 for database keys
- Index locality. New rows are added at the end of the B-tree index, as with an auto-increment number, instead of at random places. This means fewer page splits, better cache use and faster inserts on large tables.
- Sorting by time without a second column.
ORDER BY idreturns rows in about the order they were created. - No central counter. Every application server can make ids on its own, which suits distributed systems and offline clients.
The cost is that a v7 UUID reveals when it was created, to the millisecond. If the creation time of a record must stay private, use a UUID v4 instead.
Several UUIDs in the same millisecond
Within one millisecond the time part is the same, so order depends on the other bits. RFC 9562 allows using the 12 rand_a bits as a counter. This generator does that: when it makes many UUIDs in a burst, the counter rises by one for each, and if it runs out, the timestamp moves forward by one millisecond. As a result the UUIDs from one page load are strictly increasing. Try the "100 in one burst" button and check that the list is already in order.
UUID v7 against ULID and Snowflake ids
| UUID v7 | ULID | Snowflake | |
|---|---|---|---|
| Size | 128 bits | 128 bits | 64 bits |
| Time | 48-bit ms | 48-bit ms | 41-bit ms from a custom epoch |
| Text form | 36 characters (hex) | 26 characters (Crockford Base32) | Number |
| Standard | RFC 9562 | Community spec | Not a standard, needs worker ids |
| Native column types | Yes, uuid | No | Yes, bigint |
UUID v7 is the choice when you want a standard id that every database and language already understands.
Create a UUID v7 in code
// JavaScript (simple, not monotonic inside one millisecond)
function uuidv7() {
const b = crypto.getRandomValues(new Uint8Array(16));
const ms = BigInt(Date.now());
for (let i = 0; i < 6; i++) b[i] = Number((ms >> BigInt(40 - 8 * i)) & 255n);
b[6] = (b[6] & 0x0f) | 0x70;
b[8] = (b[8] & 0x3f) | 0x80;
const h = [...b].map(x => x.toString(16).padStart(2, '0')).join('');
return h.replace(/^(.{8})(.{4})(.{4})(.{4})(.{12})$/, '$1-$2-$3-$4-$5');
}
# Python 3.14 and later
import uuid; uuid.uuid7()
// C# (.NET 9 and later)
Guid.CreateVersion7();
// Go (github.com/google/uuid)
uuid.NewV7()
// Rust (uuid crate with the v7 feature)
Uuid::now_v7()
-- PostgreSQL 18 and later
SELECT uuidv7();
Older runtimes need a library. Always test that the version you use is monotonic if you rely on strict order.
Storing UUID v7
Use the native uuid type in PostgreSQL, BINARY(16) in MySQL and MariaDB (16 bytes, and the byte order keeps the time order), and avoid CHAR(36) for large tables. SQL Server sorts uniqueidentifier values in an unusual byte order, so a v7 value does not stay in time order there unless you store it as binary.
More on versions, collisions and storage: What is a UUID?, or the full UUID generator.