What Is UUID v7?
UUID Version 7 is a Unix epoch time-ordered unique identifier defined in RFC 9562, ratified by the IETF in May 2024. It encodes a 48-bit Unix millisecond timestamp in the most significant bits, followed by 74 bits of cryptographic randomness. The result is an identifier that is both globally unique and lexicographically sortable by creation time.
A UUID v7 looks like: 018e3a5f-2b4c-7d8e-9f0a-1b2c3d4e5f60. The 7 in the third group identifies the version. The first 12 hex characters encode the Unix timestamp in milliseconds — so UUIDs generated later will always sort after UUIDs generated earlier.
The Internal Structure of UUID v7
The 128 bits of UUID v7 are organized as:
- →unix_ts_ms (48 bits): Unix timestamp in milliseconds. Covers dates from 1970 to the year 10889. Appears first — this is what makes v7 sortable.
- →ver (4 bits): Version field, set to
0111(7). - →rand_a (12 bits): Random bits. Can optionally encode sub-millisecond precision or a monotonic sequence counter.
- →var (2 bits): Variant field, set to
10(RFC 4122 variant). - →rand_b (62 bits): Additional random bits for uniqueness.
Total randomness: 74 bits (12 + 62). This gives UUID v7 approximately 1.9 × 10²² possible values per millisecond — more than sufficient for any real-world generation rate.
Why UUID v7 Is the Best Choice for Database Primary Keys
The most significant practical advantage of UUID v7 is its impact on database performance. In any B-tree index (PostgreSQL, MySQL InnoDB, SQL Server, SQLite), the efficiency of INSERT operations depends heavily on where new records are inserted in the index:
The UUID v4 Problem: Index Fragmentation
UUID v4 is fully random. Each new record is inserted at a random position in the B-tree. When an index page is full and a new record needs to be inserted in the middle, the database must split the page — copying half the records to a new page. This is called a page split. At scale, frequent page splits cause:
- →High write amplification (each INSERT triggers multiple disk writes)
- →Index fragmentation (pages are partially filled, wasting space)
- →Degraded read performance (more pages to scan for range queries)
- →Increased buffer pool pressure (random pages evicted from cache)
The UUID v7 Solution: Sequential Appends
UUID v7 starts with the current Unix timestamp. New records always have a larger timestamp than existing records, so they are always inserted at the end of the B-tree index. Pages fill sequentially, splits are rare, and the index remains compact and efficient. This is the same behavior as auto-incrementing integers — but with global uniqueness and no central counter.
Real-world benchmarks on PostgreSQL with 100 million rows show UUID v7 achieving 2–5x better INSERT throughput compared to UUID v4, with 60–80% less index bloat.
UUID v7 Monotonicity Within a Millisecond
A potential concern with millisecond-precision timestamps is that multiple UUIDs generated within the same millisecond might not be ordered correctly. RFC 9562 addresses this with the rand_a field, which can be used as a monotonic counter within a millisecond.
When generating multiple UUIDs in the same millisecond, implementations can increment the rand_a counter for each UUID, ensuring strict monotonic ordering even at very high generation rates. Our generator uses random rand_a bits, which is sufficient for most applications — the probability of two UUIDs in the same millisecond being out of order is negligible for typical generation rates.
UUID v7 Adoption: Databases and Libraries
Since RFC 9562's ratification in May 2024, UUID v7 support has been rapidly adopted:
- →PostgreSQL 17+:
gen_random_uuid()still generates v4; use thepg_uuidv7extension for v7. - →MySQL 8.4+: No native v7 function yet; generate client-side and store as
BINARY(16). - →Python:
uuid-utilspackage providesuuid_utils.uuid7() - →Node.js:
uuidv7npm package - →Go:
github.com/google/uuidv1.6+ supportsuuid.NewV7() - →Rust:
uuidcrate withv7feature flag - →Laravel (PHP):
Str::orderedUuid()generates a time-ordered UUID (v7-compatible)
Extracting the Timestamp from UUID v7
Because the Unix timestamp is in the first 48 bits, extracting the creation time from a UUID v7 is straightforward:
function uuidv7ToDate(uuid) {
const hex = uuid.replace(/-/g, '').slice(0, 12);
const ms = parseInt(hex, 16);
return new Date(ms);
}
// → 2024-05-15T10:30:00.123Z
UUID v7 vs. ULID: A Direct Comparison
Both UUID v7 and ULID are time-ordered 128-bit identifiers with similar properties. The key differences:
- →Format: UUID v7 uses hex with hyphens (36 chars); ULID uses Crockford Base32 (26 chars).
- →Standard: UUID v7 is an IETF RFC standard; ULID is a community specification.
- →Database support: UUID v7 has native type support in more databases; ULID is typically stored as
VARCHAR(26)orBINARY(16). - →URL ergonomics: ULID is shorter and has no hyphens, making it slightly better for URLs.
For most applications, UUID v7 is the better long-term choice due to its official RFC status and growing native database support. Use ULID when URL length is a priority.