
PostgreSQL 18’s uuidv7() Makes Time-Ordered UUIDs a Better Default
Why PostgreSQL 18’s new uuidv7() function matters for primary keys, B-tree locality, and managed PostgreSQL rollout decisions.
If your application already uses UUIDs, PostgreSQL 18 gives you a better default than random version 4 values for new rows: uuidv7(). The reason this matters is simple. UUIDv4 is safe and convenient, but it spreads inserts across the index. UUIDv7 keeps the same distributed generation story while making new values time-ordered, which is friendlier to the B-tree indexes that PostgreSQL uses by default.
That sounds like a small change. In practice, it affects how hot indexes grow, how much random page churn your write path creates, and how much thought you have to give to primary key generation in managed PostgreSQL. For teams that want database-generated identifiers without giving up performance discipline, this is the kind of release note worth paying attention to.
Why this release matters
PostgreSQL 18 adds a built-in uuidv7() function that generates version 7 UUIDs. The release notes call them timestamp-ordered UUIDs, and the function docs explain that the timestamp combines Unix time with millisecond precision, sub-millisecond precision, and random bits. In other words, the identifier is still globally unique and still opaque enough for normal application use, but new values arrive in a roughly increasing order.
That order is useful because PostgreSQL’s default B-tree indexes are built around sortable keys. The index docs explain that B-trees can produce sorted output and that they store entries in ascending order by default. A key that grows in roughly time order is easier for the index to absorb than a fully random one.
UUIDv4, uuidv7, and bigint keys compared
| Key style | Generation pattern | Best strength | Main tradeoff |
|---|---|---|---|
| UUIDv4 | Random | Very easy to generate anywhere, with no coordination | Random inserts are harder on B-tree locality |
| uuidv7 | Time-ordered with random bits | Better index locality without giving up distributed generation | Slightly more structured, so it is not as opaque as UUIDv4 |
| bigint / serial | Central sequence | Compact, simple, and naturally ordered | Requires a sequence source and is less convenient across systems |
For many managed PostgreSQL teams, uuidv7 lands in a practical middle ground. It keeps the application architecture simple, avoids a single central allocator for every ID, and behaves more like the kind of key a B-tree prefers.
Why time order helps PostgreSQL
PostgreSQL’s B-tree implementation rewards keys that arrive in an order the tree can follow. The PostgreSQL docs for index ordering say that B-tree indexes store entries in ascending order by default, and the UUID RFC says UUIDv7 is designed so database indexes can sort it as opaque raw bytes without parsing. The same RFC also notes that time-ordered monotonic UUIDs benefit from greater database-index locality because new values are near each other in the index.
That locality matters because random inserts force the index to touch more scattered pages. Time-ordered inserts are not magic, but they usually produce a gentler growth pattern. The practical benefit is less about theoretical elegance and more about avoiding unnecessary write-path noise when the table starts getting real traffic.
What PostgreSQL 18 actually changed
The function itself is the headline. PostgreSQL 18 includes uuidv7() alongside the older uuidv4() helper, and the new function can take an optional shift interval. Most applications will not need that optional parameter, but it is available when a caller needs to shift the computed timestamp.
The important operational point is that PostgreSQL now ships a native way to generate time-ordered UUIDs inside the database. That means new projects do not need to bolt on a custom extension or rely on client-side libraries that each team implements differently. For managed PostgreSQL, reducing that variability is valuable on its own.
How to adopt uuidv7() without a risky migration
The safest adoption pattern is boring: change the default for new rows, not the historical IDs you already store. Existing UUIDv4 values can stay in place. The point is to make future inserts friendlier to your indexes, not to rewrite the past.
If you want the database to generate the key, the migration usually looks like this:
alter table orders
alter column id set default uuidv7();
If your app currently generates UUIDs in code, you can move that responsibility into the database for new writes while keeping the column type the same. That helps the application stay portable and removes one source of version skew between services, workers, and scripts.
| Rollout step | What to do | Why it helps |
|---|---|---|
| New tables | Use uuidv7 as the default for primary keys | You get the benefit from day one |
| Existing tables | Change only the default for future inserts | No need for a disruptive rewrite |
| API contracts | Keep IDs opaque and treat them as identifiers only | Prevents accidental business logic around the UUID shape |
| Staging | Test inserts, indexes, and backup restore flows | Confirms the change is operationally boring |
Where uuidv7 is not the answer
uuidv7 is a better default for many systems, but it is not a universal one. If your application uses identifiers as secrets, do not treat any UUID format as an authorization mechanism. If your bottleneck is connection pressure rather than key generation, you still need pooling. And if your slow query is caused by a bad join or a missing index, changing the UUID format will not fix it.
That is why this release should be read as a design upgrade, not a performance miracle. PostgreSQL 18 gives you a better primary-key option, but the rest of the stack still matters. If your app is connection-heavy, our PgBouncer and PostgreSQL Connection Pooling guide is the right companion read.
A practical decision guide
| Situation | Better choice | Why |
|---|---|---|
| New service with PostgreSQL 18 | uuidv7 | Simple default, better index locality |
| Existing UUIDv4 table that already works | Keep UUIDv4 for old rows, switch defaults for new rows | Low risk and no data rewrite |
| System that needs globally unique IDs across many writers | uuidv7 | Distributed generation without a central sequence bottleneck |
| System that depends on tiny, strictly monotonic integers | bigint | Smaller storage and the simplest sort order |
The useful question is not whether uuidv7 is universally best. It is whether the key shape matches how the table is written and read. For most modern app tables that already prefer UUIDs, PostgreSQL 18 finally gives a more index-friendly default.
Takeaway
If your team likes UUIDs because they are easy to generate and hard to collide, PostgreSQL 18’s uuidv7() gives you most of that convenience with a better write pattern for B-tree indexes. That makes it worth considering for new tables and for new defaults on existing tables.
The right migration is small: keep the type, change the default, validate in staging, and leave the old identifiers alone. That is a practical release-driven improvement, which is exactly the kind of news managed PostgreSQL teams should pay attention to.
Sources / further reading
- PostgreSQL 18 release notes: https://www.postgresql.org/docs/18/release-18.html
- PostgreSQL UUID functions: https://www.postgresql.org/docs/current/functions-uuid.html
- PostgreSQL indexes and ORDER BY: https://www.postgresql.org/docs/current/indexes-ordering.html
- PostgreSQL B-tree index overview: https://www.postgresql.org/docs/current/indexes-types.html
- RFC 9562, UUIDs, especially sorting and database considerations: https://www.rfc-editor.org/rfc/rfc9562.txt
Topic
News
Updated
May 21, 2026
Read time
10 min read
ArmorDB Engineering writes about PostgreSQL operations, security, and infrastructure decisions for teams building production apps on ArmorDB.
Read next
Tech-News · 7 min read
PostgreSQL 19 Beta 1: What Managed PostgreSQL Teams Should Test Now
PostgreSQL 19 Beta 1 previews changes in maintenance, replication, security, and observability that managed PostgreSQL teams should evaluate before the final release.
Read articleData-Specs · 8 min read
PostgreSQL JSONB vs Relational Tables: How to Choose the Right Schema
A practical comparison of PostgreSQL JSONB, relational columns, and hybrid schemas for SaaS teams deciding what to model, index, and constrain.
Read article