Toolsy
Back to blog

Guides

UUID v4 vs v7 for databases and APIs: when sortable IDs help

11 min read

Primary keys and public IDs need uniqueness without a central allocator. UUID v4 has been the default for years: 122 bits of randomness, no coordination, terrible B-tree locality because inserts scatter across the index. UUID v7 (RFC 9562) adds a Unix millisecond timestamp in the high bits so new IDs sort roughly by creation time while keeping random tail bits. Search interest for uuid v4 vs v7 is modest (about 90 US monthly searches) but precise; the head term uuid generator is huge (22200/mo) and belongs to the tool page, not this article. Use UUID generator when you need strings now. Use this guide when you choose a version for Postgres, MySQL, or API design.

What changed with UUID v7

UUID v4 is almost entirely random. UUID v7 encodes creation time in the most significant bits, then fills the rest with random data. Strings still look like xxxxxxxx-xxxx-7xxx-xxxx-xxxxxxxxxxxx with version nibble 7.

The goal is ordered inserts without going back to auto-increment integers exposed on the public internet. v7 is not a timestamp you should parse for business logic; it is an index-friendly identifier with uniqueness properties similar to v4’s tail.

Libraries and databases added v7 support after RFC 9562 (2024). Check your language package and DB version before you assume uuid_generate_v7() exists.

Random v4 vs time-ordered v7 for indexes

B-tree indexes on random UUID primary keys cause page splits and scattered leaf pages. Write-heavy tables (events, messages, audit rows) feel it as insert latency and larger indexes. Sequential integers (or time-ordered UUIDs) cluster new rows toward one side of the tree.

v7 trades a little predictability for locality. The first bits move forward with clock time, so recent IDs sort together in lexicographic and binary comparisons when you use them as primary keys.

v4 still wins when you want maximum opacity and you do not care about insert order. Read-heavy tables with rare inserts barely notice either choice.

Postgres and practical index behavior

On PostgreSQL, uuid primary keys with v4 often fragment btree pages under burst inserts. v7 reduces random leaf placement; benchmarks vary by hardware and fillfactor. Measure your workload instead of copying blog charts.

If you already shard or use bigint internally with a public UUID alias, index locality on the alias may matter less. Many APIs expose UUID while the database uses sequences per shard.

Collision risk and entropy

UUID v4 collision risk is negligible for practical deployments if you generate with a good RNG. v7 keeps random bits in the low section; collision resistance remains astronomically small for single-region apps.

Clock rollback or duplicate millisecond bursts are the v7 edge cases. Quality generators increment randomness or sequence bits when multiple IDs are minted in the same millisecond. Do not hand-roll v7 from Date.now() alone in hot loops.

When to stay on UUID v4

Stay on v4 when IDs must reveal no creation order to clients, when you integrate with legacy systems that only accept v4, or when write volume is low and index fragmentation is unmeasured noise.

Security-through-obscurity is weak, but some teams avoid sortable public IDs so competitors cannot scrape “newest” rows by walking UUID order. If that threat matters, v4 or opaque random tokens still fit.

Greenfield without v7 library support: ship v4 today; migrate when ORM and database versions align.

When UUID v7 helps APIs and databases

Pick v7 for append-mostly tables where UUID is the primary key and insert rate matters: event logs, chat messages, outbox rows, analytics facts. Pair with created_at columns anyway; v7 is not a replacement for audit timestamps you query in SQL.

Public APIs that list “recent resources” by ID sort benefit lexicographically when IDs are v7 and you sort descending. Do not rely on ID order across regions with clock skew without testing.

MySQL, SQL Server, and application-side generation

Postgres 18+ discussions and extensions aside, many teams generate UUIDs in application code (Node uuid, Python uuid6/uuid7 packages) and store as char(36) or binary uuid types. Confirm driver encoding and index type (btree vs clustered PK on SQL Server).

SQL Server’s uniqueidentifier defaults historically favored v4. v7 works when generated in app layer and inserted explicitly.

Generating and validating in apps

Use maintained libraries for v7; do not paste RFC bit diagrams into production. For manual QA, fixtures, and docs, UUID generator on Toolsy emits v4 and v7 in the browser without signup.

Validate string format on API input (8-4-4-4-12 hex, version nibble). Reject uppercase/lowercase mix only if your style guide cares; databases usually normalize.

Store as native uuid type where available instead of varchar when every driver supports it. Index foreign keys the same version as parent rows.

Public IDs in URLs and logs

UUIDs in URLs are guess-resistant for v4. v7 raises theoretical “next ID” scraping if an attacker knows clock skew and your generator’s random tail size. Rate limits and auth still matter more than version choice.

Log IDs as strings consistently. Truncate in user-facing error messages if length hurts support UX.

Migration strategies

Migrating live primary keys is painful. Prefer v7 for new tables and new microservices first. Avoid rewriting billion-row PKs unless metrics prove fragmentation cost exceeds migration risk.

Dual-write periods (accept v4 and v7 during rollout) complicate ORMs. If you must migrate, add id_v7 column, backfill with batch jobs, swap PK in a maintenance window, and reindex.

Security and guessing attacks

Neither v4 nor v7 replaces authentication. Treat IDs as identifiers, not secrets. For session tokens or password reset links, use dedicated high-entropy secrets, not UUID v4 alone.

Sortable IDs leak coarse creation order. If that is a product risk (bids, private drafts), use random IDs or internal surrogate keys.

Frequently asked questions

What is the difference between UUID v4 and v7?

v4 is random. v7 embeds a timestamp in the high bits and random bits in the rest, so new IDs tend to sort by creation time. v7 can improve B-tree insert locality; v4 hides creation order slightly better.

Should I use UUID v7 for Postgres primary keys?

Consider v7 for write-heavy tables where UUID is already your PK and you see insert or index bloat with v4. Keep created_at for queries. Verify generator and Postgres version support before migrating production.

Is uuid generator the same topic as v4 vs v7?

No. “UUID generator” is transactional tool intent (22200/mo searches). This article is informational scenario content for architects choosing a version. Generate sample strings at UUID generator.

Does UUID v7 replace auto-increment integers?

Not always. Integers are still smaller and faster for internal-only keys. v7 helps when you need opaque string IDs at scale without a central sequencer.

Are UUID v7 values sortable as strings?

Lexicographic sort on canonical hex string form roughly follows creation order for IDs from the same generator. Cross-system sort is not a guaranteed timeline.

What is a sortable UUID?

Usually UUID v7 or other time-ordered schemes (ULID, Sonyflake). Ads volume for “sortable uuid” is small (~20/mo) but maps to the same design question.

Can I use UUID v7 in public APIs?

Yes, when ordered IDs are acceptable and libraries are supported. Document that clients must not parse IDs as timestamps. Enforce auth on sensitive resources regardless of ID version.

How do I generate UUID v7 for tests?

Use UUID generator for quick copies or your language’s v7-capable package in CI fixtures. Avoid hardcoding one ID across all tests; uniqueness constraints will fail.

Will migrating from v4 to v7 shrink my database?

Unlikely by itself. Benefits are mostly insert performance and index behavior, not storage halving. Measure fragmentation and write latency before a large migration.

Does Toolsy store generated UUIDs?

Browser generation on UUID generator runs client-side for copy-out use. Treat generated IDs like any local dev utility; do not send secrets you would not paste elsewhere.

When you pick a version, prototype both on a staging table with your real insert rate. Generate test IDs at UUID generator, load a million rows, and read pg_stat_user_tables or your engine’s equivalent before you change production defaults.

Generate UUIDs

Create v4 or v7 UUIDs in the browser, copy, and paste into schemas or API fixtures.

Open UUID generator
Share this article

More to read

UUID v4 vs v7 for databases and APIs: when sortable IDs help — Toolsy