Email me

Explainer · 7 min read

Filed under App development Rust

UUIDv7 vs UUIDv4: which should you use?

Short answer

Use UUIDv7 for database primary keys and anything you sort or index by ID: it starts with a millisecond timestamp, so new IDs always land at the end of the index instead of at random spots. In our test on a 5-million-row table, inserting with random UUIDv4 keys took 176.6 seconds against 11.0 seconds for v7, 16 times slower. Use v4 when the ID must reveal nothing, not even when the record was made.

Line chart titled Random UUIDs get slower as the table grows, v7 stays flat. Milliseconds to insert each 50,000-row batch into a SQLite table keyed by a UUID, over 5 million rows. The UUIDv4 line climbs from about 80 ms to about 2,500 ms per batch, 177 seconds total. The UUIDv7 line stays flat at about 80 ms, 11 seconds total.
Our test: same table, same machine, only the ID changes. Random v4 keys get slower as the index outgrows memory; v7 keys stay flat. Chart: Tensorust, from our benchmark run on Oct 23 2026 (data in the CSV).

Part of the article Pick a UUIDv7 library that keeps order: 10 tested, .NET fails 50%. This page answers one question from it in depth.

On this page · 10 sections
  1. Key facts
  2. The two layouts
  3. What we measured
  4. Why random keys get slow
  5. When v4 is still the right call
  6. Common misconceptions
  7. Our take
  8. Related
  9. FAQ
  10. Sources

Both are the same 16 bytes and fit the same uuid column, so this is a choice about what the bits mean, not about storage. Below: the layouts, our benchmark, why the gap appears, and the catches with v7 that our test of 10 UUIDv7 libraries turned up.

Key facts

What Number Source (checked Oct 23 2026)
Size of both 128 bits (16 bytes) RFC 9562
UUIDv4 random bits 122 RFC 9562, section 5.4
UUIDv7 layout 48-bit Unix ms timestamp, 4 version bits, 12 + 62 bits of counter or random, 2 variant bits RFC 9562, section 5.7
RFC 9562 published May 2024 RFC Editor
Built into PostgreSQL uuidv7() since PostgreSQL 18 PostgreSQL 18 docs
Insert 5M rows, UUID as primary key v4 176.6 s, v7 11.0 s (16x) our test, Oct 23 2026
Insert 5M rows, UUID in a secondary index v4 80.6 s, v7 12.6 s (6.4x) our test
Last 500,000 rows, per 50,000 batch v4 2,482 ms, v7 81 ms our test
File size after 5M rows (primary key) v4 701.4 MB, v7 697.5 MB our test
UUIDv7 libraries that kept order and a true clock 2 of 10 tested our library test

Download the data: every batch time for all four runs.

The two layouts

Diagram titled Same 128 bits, different order of business. UUIDv4: 48 random bits, 4 version bits, 12 random bits, 2 variant bits, 62 random bits, 122 random in total. UUIDv7: 48-bit Unix time in milliseconds, 4 version bits, a 12-bit counter, 2 variant bits, 62 random bits.
Byte order is time order for v7, and pure chance for v4. Credit: Tensorust diagram from RFC 9562.

A v4 ID is 122 random bits with 6 fixed bits marking the version and variant. Two v4 IDs made a millisecond apart are as far apart in sort order as two made a year apart.

A v7 ID puts the current Unix time in milliseconds in the first 48 bits, so sorting v7 IDs as bytes sorts them by when they were made. The remaining 74 bits are random, or partly a counter that keeps IDs from the same millisecond in order. The RFC leaves that choice to the library, which is why libraries differ more than people expect (more on that below).

What we measured

We inserted 5 million rows into SQLite with Python, in batches of 50,000 with one commit per batch, twice per ID type: once with the UUID as the table's primary key (a WITHOUT ROWID table, so the rows are stored in UUID order, the way InnoDB and SQL Server clustered keys work) and once with an integer key plus a unique index on the UUID (closer to a default Postgres table). The page cache was 64 MB. Everything else was identical.

Run Total time Slowest part
v4, UUID primary key 176.6 s 2.5 s per batch near the end
v7, UUID primary key 11.0 s flat, about 80 ms per batch
v4, UUID secondary index 80.6 s 1.3 s per batch near the end
v7, UUID secondary index 12.6 s flat, about 85 to 117 ms per batch

The v4 runs start just as fast as v7. The gap opens as the index grows past what the cache can hold, and it keeps widening: by the last batches each v4 batch took about 30 times longer than a v7 batch.

One thing did not change: size. The v4 table ended at 701.4 MB and the v7 table at 697.5 MB. SQLite rebalances neighboring pages when it splits, so random inserts did not leave it much emptier. Other databases split pages differently, and random keys are known to leave more half-empty pages in some of them; we did not measure that here.

Why random keys get slow

Diagram titled Why: where each new key lands in the index. A row of 24 leaf pages. UUIDv4: 8 inserts touch 8 different leaf pages scattered across the row; each page must be read, changed and written back, and once the index is bigger than the cache most inserts wait on disk. UUIDv7: 8 inserts all land on the last leaf page, which stays in cache and fills up before a new page starts at the right edge.
Random keys spread writes across the whole index; time-ordered keys append. Credit: Tensorust diagram (simplified).

Database indexes are B-trees: keys are kept in sorted order on fixed-size pages. Each insert has to find the page where its key belongs, change it and eventually write it back.

With v4, that page is anywhere. While the index fits in memory this barely matters. Once it does not, almost every insert needs a page that is not cached, so it waits for a read and pushes another page out. With v7, the right page is nearly always the last one, which is already in memory. Writes become appends.

This is the same reason auto-increment integers have always been fast keys. UUIDv7 gets most of that speed while still letting any server, phone or browser create IDs without asking the database for the next number.

When v4 is still the right call

  • The ID must not leak time. Anyone holding a v7 ID can read when it was made: paste the first 12 hex digits into our Unix timestamp converter as hex milliseconds, or call uuid_extract_timestamp() in Postgres. For signup IDs, invoice numbers or anything where creation time is private, that is a leak.
  • The ID doubles as a secret. v7 has fewer random bits than v4's 122, and some libraries spend more of them on a counter: in our library test the fresh random bits per ID ran from 74 down to 32. For password-reset tokens or invite links, use a dedicated random token, not any UUID.
  • Small tables. If the table will never outgrow memory, the insert gap in our chart never opens.

Common misconceptions

Myth

"UUIDv7 IDs are always in order."

The recordOnly if the library keeps a counter inside each millisecond. Microsoft's Guid.CreateVersion7() does not, and 50% of its IDs sorted out of order in a tight loop in our library test.

Myth

"The timestamp inside a UUIDv7 is the creation time."

The recordThe spec lets libraries alter it. One popular Python package ran 16.6 minutes ahead of the real clock under load, and another writes a pre-standard layout that decodes to the year 2202. Treat it as approximate.

Myth

"UUIDv4 wastes more space than UUIDv7."

The recordBoth are 16 bytes. In our test the two tables ended within 1% of each other in size; the difference was time, not space.

Myth

"Switching to v7 means a new column type."

The recordNo. v7 values go into the same uuid or binary(16) column as v4. Watch byte order in .NET, where Guid.ToByteArray() writes the first bytes little-endian unless you pass bigEndian: true.

FAQ

What is the difference between UUIDv4 and UUIDv7?

Both are 128-bit IDs in the same format. UUIDv4 is 122 random bits. UUIDv7, standardized in RFC 9562 in May 2024, starts with a 48-bit Unix timestamp in milliseconds followed by 74 bits of random data or a counter, so v7 IDs sort by creation time.

Is UUIDv7 faster than UUIDv4 for database inserts?

Usually, once the table is large. In our test inserting 5 million rows into a SQLite table keyed by the UUID, v4 took 176.6 seconds and v7 took 11.0 seconds. Random v4 keys land all over the index, so inserts slow down once the index no longer fits in memory.

Is UUIDv7 secure enough to expose in URLs?

It is unguessable enough for most uses, but less random than v4 and it reveals when the record was created. If anyone who changes an ID in a URL can read someone else's data, the problem is missing access control, not the ID format.

Does PostgreSQL support UUIDv7?

Yes. PostgreSQL 18 added a built-in uuidv7() function and uuid_extract_timestamp() reads the time back out. Older versions need an extension or IDs generated in the application.

Should I switch existing UUIDv4 keys to UUIDv7?

Only if insert speed or index size is a measured problem. Both fit the same uuid column, so new rows can use v7 while old rows keep v4, but the old part of the index stays random.

Sources

All checked October 23, 2026.

Specs and docs

Our data

  • The benchmark behind every number in the "What we measured" section: Python 3.12.10 with SQLite 3.49.1 on an Intel i7-13700KF under Windows 11, run October 23, 2026. 5,000,000 rows per run, 100 batches of 50,000 rows with a 100-byte text payload, one commit per batch, WAL journal, synchronous=NORMAL, 64 MB page cache. v4 IDs from Python's uuid.uuid4(); v7 IDs built to the RFC 9562 layout (48-bit millisecond time, 12-bit counter, 62 random bits). All batch times are in data.csv.
  • Library behavior (out-of-order rates, timestamp drift, random bits per library): our article Pick a UUIDv7 library that keeps order: 10 tested, October 23, 2026.

Credit

Images

  • Benchmark chart, layout diagram and B-tree diagram: made by Tensorust with matplotlib.

Next question

Every number on this page links to its source and was checked on Oct 23, 2026. Spot an error or a newer figure? Email matt@tensorust.com and it gets fixed. Related: Unix timestamp converter.

Read next

Back to The Manual →   All articles →

Get the next one by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Get the receipts by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Did this answer your question?

Popular in the shop

All 124 tools →

Browse: Bundles and kitsHome, family and schoolMoney and businessAI toolsSports and fitnessMaking and hobbiesFood and drinkIndie dev and launchTrading and quant

Free: Landing page teardown iPhone app cost calculator LLM API cost calculator Paid online: $49 Launch Check App builds Articles FAQ