UUID v4 vs v7: which one should you use?
· 6 min read
For years the default answer to “what id should I use” was UUID v4: generate 122 random bits, never coordinate with anyone, never collide. It still works. But on large tables, those random ids have a cost in index size and write speed, and in 2024 the new UUID spec made a time-ordered alternative official.
This article explains how UUIDs are structured, how to read the version from any UUID at a glance, and how to choose between v4 and v7. The UUID generator and inspector generates both versions and decodes any UUID you paste, including the timestamp inside a v7.
What a UUID is
A UUID is a 128-bit number, written as 32 hex digits in five groups:
017f22e2-79b0-7cc3-98c4-dc0c0c07398f
The groups are 8, 4, 4, 4 and 12 hex digits long.
The format and versions are defined by RFC 9562 (May 2024), which replaced the original RFC 4122. Two positions are fixed in every standard UUID:
- The version is the first hex digit of the third group. In the example above that’s
7. - The variant is the first hex digit of the fourth group. For standard UUIDs it’s
8,9,aorb. Here it’s9.
So you can tell a UUID’s version without any tool: xxxxxxxx-xxxx-4xxx-... is v4, xxxxxxxx-xxxx-7xxx-... is v7.
The versions
| Version | How it’s built | Use today? |
|---|---|---|
| v1 | Timestamp (100 ns since 1582) + MAC address | Legacy; leaks the machine’s MAC |
| v3 | MD5 hash of a namespace and a name | Prefer v5 |
| v4 | 122 random bits | Yes: the general-purpose default |
| v5 | SHA-1 hash of a namespace and a name | Yes, for deterministic ids from names |
| v6 | v1 with the timestamp reordered for sorting | Only for compatibility with v1 systems |
| v7 | Unix timestamp in ms + 74 random bits | Yes: the default for database keys |
| v8 | Custom layout, vendor-defined | Only for your own schemes |
There are also two special values: the nil UUID 00000000-0000-0000-0000-000000000000 and, new in RFC 9562, the max UUID ffffffff-ffff-ffff-ffff-ffffffffffff.
v4: random
A v4 UUID is 122 random bits plus the 6 fixed version and variant bits. In JavaScript:
crypto.randomUUID(); // "620f0d6a-ede0-4e7b-acd2-c54147ac5291"
How likely is a collision? By the birthday bound, you’d need about 2.7 × 10^18 v4 UUIDs for a 50% chance of a single duplicate. At a billion ids per second, that’s around 86 years. In practice, collisions come from bad random number generators (a VM snapshot restored twice, a non-cryptographic Math.random() implementation), not from the math. Use the platform’s cryptographic generator and you can stop worrying.
The problem with random keys in databases
Most databases store primary keys in a B-tree index. B-trees are happiest when new keys arrive in order: each insert goes to the rightmost page, which stays in memory, and pages fill up completely.
Random v4 keys land at a random place in the index every time. On a table larger than memory, that means:
- inserts touch pages all over the index, so fewer of them are cached and more reads hit disk
- pages split in the middle, leaving them about half full, so the index grows larger than it needs to be
- recently inserted rows sit far apart, so “latest rows” queries don’t benefit from locality
On small tables none of this is noticeable. On tables with hundreds of millions of rows, the difference in insert speed and index size can be large, so measure it on your own workload before and after a change.
v7: time-ordered
A v7 UUID starts with a 48-bit Unix timestamp in milliseconds, followed by the version, the variant and 74 random bits:
017f22e2-79b0-7cc3-98c4-dc0c0c07398f
^^^^^^^^ ^^^^ 48-bit timestamp (milliseconds)
^ version: 7
^ variant: 8, 9, a or b
Everything else is random: 74 bits in total.
The first 12 hex digits are the time. For the example UUID above, 017f22e279b0 in hex is 1645557742000 milliseconds, which is 2022-02-22 19:22:22 UTC. The UUID inspector does that decoding for you, and the timestamp converter shows what the millisecond value means. (Reading hex digits as a number is exactly what the number base converter is for.)
Because the timestamp comes first, v7 UUIDs generated later sort after earlier ones, as strings and as bytes. For a database, that means new keys go to the end of the index, as with an auto-increment integer, while keeping every other UUID property: generated anywhere, no coordination, no collisions in practice.
Support
v7 is new enough that support varies:
- PostgreSQL 18 added a built-in
uuidv7()function. On older versions, use an extension or generate ids in the application. - Most languages have libraries (
uuidon npm supportsv7(), as do Python’suuid6package and Java’suuid-creator). Python 3.14 addsuuid.uuid7()to the standard library. crypto.randomUUID()in browsers and Node.js still only produces v4.
What v7 gives away
The timestamp is readable by anyone who sees the id. If your ids appear in URLs, a v7 reveals when each record was created, and roughly how many records per second you create if someone collects enough of them. For order numbers, user ids in public URLs or anything where creation time is sensitive, that may matter. v4 reveals nothing.
v7 is also less random: 74 bits instead of 122. That’s still far beyond what you need for uniqueness, but don’t use a UUID of any version as a secret token. Session ids, password reset links and API keys should come from a dedicated random generator with at least 128 bits of entropy.
Storage tips
- Store UUIDs in a native type (
uuidin PostgreSQL) or as 16 bytes (BINARY(16)in MySQL), not as 36-character text. Text takes more than twice the space and compares more slowly. - In MySQL,
UUID_TO_BIN(uuid, 1)reorders v1 timestamps for better locality. With v7 you don’t need the swap; the order is already right. - Case doesn’t matter.
017F22E2-...and017f22e2-...are the same UUID, but compare them after normalising, or in a native type.
Which one to use
| Situation | Choice |
|---|---|
| Primary keys in a large, write-heavy table | v7 |
| Ids exposed publicly where creation time is sensitive | v4 |
| The same input must always produce the same id | v5 (name-based) |
| Nothing special, small tables, existing v4 everywhere | v4 is fine, no need to migrate |
Need a batch of ids for a test fixture, or want to check what’s inside an id from a log? The UUID generator creates up to 1,000 v4 or v7 UUIDs at once and decodes the version, variant and timestamp of any UUID you paste.