UUID Version 7 (Time-Ordered)
Understand UUID v7 from RFC 9562: a time-ordered UUID with millisecond precision that combines sortability with randomness for database-friendly IDs.
Detailed Explanation
UUID Version 7, introduced in RFC 9562 (May 2024), is a time-ordered UUID designed to solve the database indexing problems inherent in UUID v4. It embeds a Unix timestamp with millisecond precision in the most significant bits, making v7 UUIDs lexicographically sortable by creation time.
Bit layout (128 bits total):
- Bits 0-47 (48 bits): Unix timestamp in milliseconds since epoch
- Bits 48-51 (4 bits): Version
0111(7) - Bits 52-63 (12 bits): Sub-millisecond precision or random data
- Bits 64-65 (2 bits): Variant
10 - Bits 66-127 (62 bits): Random data
The timestamp occupies the first 48 bits, which means the hex representation starts with a timestamp prefix. For example, a UUID v7 generated on 2024-01-15 might look like: 018d1a2b-3c4d-7e5f-a6b7-c8d9e0f1a2b3. The leading 018d... encodes the millisecond timestamp.
Why time-ordering matters for databases: B-tree indexes used in PostgreSQL, MySQL, and most databases perform best with monotonically increasing keys. UUID v7 values generated close in time will be stored near each other in the index, resulting in sequential writes rather than random writes. Benchmarks consistently show 2-10x improvement in insert throughput compared to UUID v4 on indexed columns.
Sub-millisecond ordering: When multiple UUIDs are generated within the same millisecond, the 12 bits after the version field can use a monotonic counter or random fill. A counter approach guarantees strict ordering within a millisecond, while random fill provides probabilistic ordering.
Generation example:
function uuidv7() {
const timestamp = Date.now();
const bytes = new Uint8Array(16);
// Set 48-bit timestamp
bytes[0] = (timestamp / 2**40) & 0xff;
bytes[1] = (timestamp / 2**32) & 0xff;
bytes[2] = (timestamp / 2**24) & 0xff;
bytes[3] = (timestamp / 2**16) & 0xff;
bytes[4] = (timestamp / 2**8) & 0xff;
bytes[5] = timestamp & 0xff;
// Fill remaining with random
crypto.getRandomValues(bytes.subarray(6));
bytes[6] = (bytes[6] & 0x0f) | 0x70; // version 7
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10
const hex = [...bytes].map(b => b.toString(16).padStart(2, '0')).join('');
return [hex.slice(0,8), hex.slice(8,12), hex.slice(12,16), hex.slice(16,20), hex.slice(20)].join('-');
}
Trade-offs: UUID v7 leaks creation time, which may be undesirable for security-sensitive contexts. The 48-bit timestamp supports dates until the year 10889, so there is no Y2K-style concern.
Use Case
UUID v7 is the best choice for database primary keys in new applications, especially in distributed systems that need both uniqueness and chronological ordering for efficient queries and pagination.