If you are picking an ID format for a new table, an API or an event stream, the choice usually comes down to two UUID versions. Version 4 is the familiar random one. Version 7 is the newer, time-ordered one, standardized in RFC 9562 in May 2024.
Both are 128 bits, both look the same at a glance, and both fit the same uuid column. The difference is in what the bits mean, and that difference matters a lot once a table gets big.
The short answer
- Use v7 for database primary keys and anything else that is inserted in large volumes and indexed. New v7 values always land at the end of the index instead of at a random spot.
- Use v4 for IDs that people outside your system can see, when you don't want to reveal when something was created. A v4 UUID carries no information at all.
- Use neither as a secret. A UUID is an identifier, not a password, session token or API key.
The rest of this article explains why, with real values you can check yourself.
What's inside a v4 UUID
A version 4 UUID is 122 random bits plus 6 fixed bits that mark the version and variant (RFC 9562, section 5.4). Here are three, made with our UUID Generator:
965f20bc-f9cc-4f1b-a7b6-6e18c0a9419b
c10761c6-a965-4fb1-880c-b66f9364a45a
7823f916-d2ce-49a2-9c44-18ab95f7e91b
The only predictable parts are the 4 at the start of the third group (the version) and the first digit of the fourth group, which is always 8, 9, a or b (the variant). Everything else is random. The three values have no relationship to each other, and nothing in them tells you which was made first.
What's inside a v7 UUID
Version 7 puts a timestamp first. Section 5.7 of the RFC defines the layout:
| Bits | Field | What it holds |
|---|---|---|
| 48 | unix_ts_ms | Milliseconds since January 1, 1970 (UTC) |
| 4 | ver | Always 7 |
| 12 | rand_a | Random bits, or a counter for ordering within one millisecond |
| 2 | var | The variant, binary 10 |
| 62 | rand_b | Random bits |
Three v7 UUIDs made in a row by the same tool:
01a13268-8fcd-7030-9e25-1fcf176351a4
01a13268-8fcd-7031-a18b-b3c70f906b65
01a13268-8fcd-7032-a3cd-d6b06aa40e81
The first 12 hex digits, 01a132688fcd, are the timestamp. In decimal that is 1791847075789 milliseconds, which you can paste into the Unix Timestamp Converter to get October 12, 2026, 23:17:55.789 UTC. All three share it because they were made in the same millisecond.
Right after the version digit 7 comes a counter: 030, 031, 032. This is one of the three ways the RFC suggests for keeping IDs in order when several are created in the same millisecond (section 6.2 calls it a "fixed bit-length dedicated counter"). The last 62 bits are still random.
The result: v7 UUIDs sort by creation time, both as raw bytes and as lowercase text.
Why random keys hurt database indexes
RFC 9562 states the problem directly in its motivation section: UUID versions that are not time-ordered, such as v4, "have poor database-index locality" (section 2.1). Here's what that means in practice.
Most databases store a primary key index as a B-tree, which keeps keys sorted in fixed-size pages. Where a new key goes depends on its value:
- With v4 keys, every insert lands at a random position. Each one touches a different page somewhere in the index. Once the index is larger than the memory the database can cache, many inserts have to read a page from disk first. Pages also fill up in random places and split, which leaves them partly empty and makes the index larger than it needs to be.
- With v7 keys, every new key is larger than the ones before it, so inserts go to the last page of the index. That page is almost always already in memory, pages fill up completely before a new one starts, and the index stays compact.
On a small table you won't notice either way. The difference shows up on tables with millions of rows and steady inserts, and it also affects anything that copies the index around, like replication and backups. Time order has a side benefit too: rows created around the same time sit near each other, so queries like "the latest 50 orders" read fewer pages.
When v4 is still the better choice
The timestamp that makes v7 good for indexes is also visible to anyone who sees the ID. If a v7 UUID appears in a URL like /invoices/01a13268-8fcd-7030-…, anyone can read off the exact millisecond the invoice was created. That can leak things you'd rather keep private, such as when an account was opened or how a series of records was spread over time.
So v4 remains the safer pick for:
- IDs shown in URLs, emails or receipts when the creation time is sensitive
- Public references to user accounts
- Small tables or low insert volume, where the index argument doesn't apply
A common pattern is to use both: a v7 primary key inside the database and a separate v4 column for the public-facing ID.
One thing neither version gives you is secrecy. The RFC's security considerations say implementations should not assume UUIDs are hard to guess, and that UUIDs "MUST NOT be used as security capabilities", meaning identifiers whose mere possession grants access. For password reset links, session IDs or API keys, use a token generated specifically for that purpose.
Will two UUIDs ever collide?
For v4, the math is the birthday problem over 122 random bits. You would need about 2.7 × 1018 UUIDs for a 50% chance of a single duplicate. That is roughly a billion UUIDs per second for 86 years.
For v7, IDs can only collide if they share the same millisecond, because the timestamp differs otherwise. Within one millisecond, a fully random v7 has 74 random bits. Even with a 12-bit counter taking up some of those bits, as in the example above, two separate generators would need around 2.5 billion IDs in the same millisecond to reach a 50% chance of a collision. Both versions are safe to generate independently on many machines.
Using v7 in your stack
PostgreSQL
PostgreSQL 18 has a built-in uuidv7() function, plus uuidv4() as an alias for the older gen_random_uuid(). It can also read the time back out:
CREATE TABLE orders (
id uuid PRIMARY KEY DEFAULT uuidv7(),
placed_at timestamptz NOT NULL DEFAULT now()
);
SELECT uuid_extract_timestamp(id) FROM orders LIMIT 1;
On older PostgreSQL versions, generate v7 values in your application and insert them into a regular uuid column.
MySQL
MySQL's UUID() function returns version 1, not 7, according to the MySQL 8.4 reference manual. Its UUID_TO_BIN(uuid, 1) option rearranges the time fields of a v1 UUID to make it index-friendly, but the manual notes this swap does nothing useful for other versions. For v7, generate the value in your application and store it with UUID_TO_BIN(uuid) without the swap flag, because v7 is already in time order.
Storage format
Whichever version you pick, store it as binary if you can. Section 6.13 of the RFC recommends storing the underlying 128-bit value, which takes 16 bytes instead of 36 characters of text. PostgreSQL's uuid type and MySQL's BINARY(16) both do this.
Switching an existing table from v4 to v7
You don't need to rewrite old IDs. A v4 and a v7 UUID fit the same column, and uniqueness isn't affected by mixing them. Change the default or the code that creates new IDs, and from that point on new rows are appended in order. The old v4 rows stay scattered through the index, but every new insert benefits right away.
Two things to check before you switch:
- Code that sorts by ID and expects random order, such as sampling with
ORDER BY id LIMIT n, will now get the newest or oldest rows instead. - Anywhere the ID is public, decide whether showing the creation time is acceptable.
FAQ
Do v7 UUIDs sort correctly as text?
Yes, as long as they are all lowercase (or all uppercase) and use the same format. The timestamp is at the front in big-endian hex, so text order matches time order. IDs from different servers are only as well ordered as those servers' clocks.
How do I find out which version a UUID is?
Look at the first digit of the third group: 4 means version 4 and 7 means version 7. Or paste it into the inspector in the UUID Generator, which also shows the creation time of v1 and v7 UUIDs.
Is a v7 UUID less random than v4?
It has fewer random bits, 74 at most compared with 122, because 48 bits hold the time. That is still far more than enough to prevent collisions, but it's another reason not to use any UUID as a secret token.
Should I use v1 or v6 instead?
No. RFC 9562 says implementations should use v7 instead of v1 and v6 if possible. Classic v1 UUIDs can also include the computer's MAC address, which the RFC flags as a privacy risk.