Cover image for PostgreSQL 18: Async I/O, uuidv7, Generated Columns, and Why Developers Should Care

At a glance

Reading time

~200 words/min

Published

1 hour ago

Jul 27, 2026

Views

3

All-time total

PostgreSQL 18: Async I/O, uuidv7, Generated Columns, and Why Developers Should Care

PostgreSQL keeps doing the rare thing in software: getting better every year without getting worse. Version 18 is a meaty release, and unusually for a database upgrade, several of its headline changes are things application developers not just DBAs will actually feel. A new asynchronous I/O subsystem, a built-in time-ordered UUID generator, more flexible generated columns, and smarter indexing each address real, everyday pain. This guide walks the changes that matter for the people writing the queries, and why they are worth an upgrade.

The changes developers will actually feel

  • Asynchronous I/O for faster reads on read-heavy workloads
  • Built-in uuidv7() time-ordered UUIDs that index well
  • Virtual generated columns computed on read
  • Skip scan, letting more queries use multicolumn indexes
  • A smoother major-version upgrade path
i

Info

Why a database release is worth your attention

Application performance is often database performance in disguise. Features that make reads faster, keys index better, and indexes apply to more queries translate directly into snappier apps without you rewriting application code. Always confirm specifics against the official PostgreSQL 18 release notes for your platform.

Asynchronous I/O: faster reads under load

Historically PostgreSQL issued disk reads one at a time and waited for each fine on fast storage with small working sets, less so when a query must pull many pages that are not cached. Version 18 introduces an asynchronous I/O subsystem that lets the database have multiple read requests in flight at once, so it spends less time waiting on storage. For read-heavy workloads, large scans, and analytical queries, this can meaningfully improve throughput, especially where data does not all fit in memory.

💡

Tip

The win is largest where you were I/O-bound

If your workload already fits in RAM, you will notice less. The biggest gains land on large tables, big sequential or bitmap scans, and queries that previously stalled waiting on the disk. As always, measure on your own data rather than assuming.

uuidv7(): the right way to do UUID keys

Developers love UUIDs for primary keys globally unique, generatable on the client, no central sequence. But traditional random UUIDs (v4) have a nasty side effect: because they are random, inserting them scatters writes across the index, causing fragmentation and poor cache behaviour as tables grow. UUIDv7 fixes this by embedding a timestamp so values are time-ordered: new rows cluster together in the index the way auto-incrementing integers do, while keeping UUID uniqueness. PostgreSQL 18 adds a built-in uuidv7() function, so you no longer need an extension or client-side library to get them.

-- Time-ordered UUID keys, built in — unique AND index-friendly.
CREATE TABLE orders (
    id          uuid PRIMARY KEY DEFAULT uuidv7(),
    customer_id bigint NOT NULL,
    created_at  timestamptz NOT NULL DEFAULT now()
);

-- New rows cluster at the "end" of the index like serial ids,
-- avoiding the write scattering that random uuidv4 causes.
💡

Pro tip

If you are choosing UUID primary keys for a new table on PostgreSQL 18, prefer uuidv7() over random v4. You keep every benefit of UUIDs while avoiding the index fragmentation and insert slowdown that random UUIDs inflict on large, write-heavy tables. It is close to a free win.

Generated columns get more flexible

Generated columns let the database compute a column from other columns automatically. Previously PostgreSQL only supported stored generated columns the value is computed on write and saved to disk. Version 18 adds virtual generated columns, computed on the fly when you read them, so they cost no storage and never go stale. This is ideal for derived values you want to query like a normal column but do not want to physically persist.

CREATE TABLE products (
    price_cents   int  NOT NULL,
    tax_rate      numeric NOT NULL,
    -- computed on read: no storage, always current with its inputs
    total_cents   int GENERATED ALWAYS AS
                  (price_cents + round(price_cents * tax_rate)) VIRTUAL
);

Pros

  • Virtual columns: derived values with zero storage cost
  • Query computed values like ordinary columns cleaner app code
  • Stored columns still available when you want them precomputed
  • The logic lives in the schema, not scattered across every query

Cons

  • Virtual values are recomputed on each read weigh read vs write cost
  • Complex expressions move work into the database; profile them
  • Behaviour and defaults differ from stored columns read the docs
  • Not a substitute for proper indexing of frequently filtered values

Skip scan: more queries use your indexes

A classic gotcha: you have a multicolumn index on (a, b), but a query filters only on b, so PostgreSQL cannot use the index efficiently and falls back to a slower scan. Version 18 improves this with skip scan, which lets the planner use such an index even when the leading column is not constrained, by effectively "skipping" through its distinct values. The practical effect is that more of your existing queries can lean on indexes you already have, without you adding new ones.

Warning

Helpful, but not a reason to stop thinking about indexes

Skip scan widens where existing multicolumn indexes apply a genuine win but it does not make index design irrelevant. Designing indexes around your real query patterns still matters. Treat skip scan as a safety net that catches more cases, not a replacement for understanding your access patterns.

A smoother upgrade path

Major PostgreSQL upgrades have long carried a hidden cost: after the upgrade, the database's query planner statistics were not carried over, so the freshly upgraded system could run with poor plans until those statistics were rebuilt sometimes a nasty performance dip right when you least want one. Version 18 improves this area so upgrades are less likely to leave you with a temporarily slow database, lowering the risk and stress of moving up a major version.

Reads

are where most apps feel the database — and 18 targets them hard

Should you upgrade?

1

New projects

Start on 18. You get uuidv7(), async I/O, and virtual generated columns from day one with no migration cost.

2

Read-heavy or I/O-bound apps

The async I/O improvements alone may justify the move benchmark your real workload to quantify the gain.

3

Write-heavy apps using UUID keys

Migrating new tables to uuidv7() can reduce index bloat and improve insert performance as you grow.

4

Any production database

Test on a copy first, verify extensions support 18, and rehearse the upgrade the smoother stats handling helps, but caution still wins.

! Common mistakes to avoid

  • Using random uuidv4 as primary keys on large tables.

    Prefer the built-in uuidv7() time-ordered values avoid the index fragmentation v4 causes.

  • Assuming async I/O helps every workload.

    The gains land on read/I/O-bound queries; if your data fits in RAM you will notice less.

  • Treating skip scan as a reason to stop designing indexes.

    It widens where existing indexes apply, but index design around real query patterns still matters.

  • Upgrading production without a tested rehearsal.

    Test on a copy, verify extensions support 18, and rehearse even with the smoother stats handling.

? Frequently asked questions

Why should developers care about PostgreSQL 18? +

Several headline features land directly in developers' hands: asynchronous I/O for faster reads, built-in time-ordered uuidv7() keys, virtual generated columns, and skip scan so more queries use existing indexes.

What is uuidv7 and why prefer it over uuidv4? +

UUIDv7 embeds a timestamp so values are time-ordered and cluster in the index like serial IDs, avoiding the write scattering and fragmentation that random UUIDv4 causes on large, write-heavy tables.

What are virtual generated columns? +

Columns computed on read rather than stored on write — they cost no storage and never go stale, ideal for derived values you want to query like a normal column without persisting them.

What does asynchronous I/O improve? +

It lets PostgreSQL keep multiple read requests in flight instead of waiting on each, improving throughput for read-heavy workloads, large scans, and data that does not fit in memory.

Is upgrading to 18 risky? +

Less than before — improvements reduce the post-upgrade performance dip from missing planner statistics. Still test on a copy, verify extension support, and rehearse the upgrade.

Success

A genuinely developer-friendly release

PostgreSQL 18 is unusual in how much of its value lands directly in developers' hands: faster reads, better UUID keys, storage-free derived columns, and indexes that apply to more queries. Adopt it for new work without hesitation, plan a tested upgrade for existing systems, and lean on uuidv7() and virtual columns the moment you are on it.

Bishrul Haq

Written by

Bishrul Haq

Software engineer writing practical tutorials on Laravel, PHP, Python, and the tools behind real projects. More about me

Newsletter

Want more posts like this?

Get practical software notes and tutorials delivered when something new is published.

No spam. Unsubscribe anytime.

How did this land?

Comments

0
Log in or sign up to join the discussion and react to this post.

No comments yet. Be the first to share your thoughts.

Related posts

Essential Sorting Algorithms for Computer Science Students

Algorithms are commonly taught in Computer Science, Software Engineering subjects at your Bachelors or Masters. Some find it difficult to understand due to memorizing.

6 years ago

GraphQL in Laravel Using Lighthouse

In modern web development, GraphQL has emerged as a powerful alternative to REST APIs due to its flexibility and efficiency.

1 year ago

Building Modern Reactive UIs with Laravel 12 and Livewire 4: A Production Guide

A production-grade walkthrough of Livewire 4 in Laravel 12 — form objects, lazy components, Alpine interop, file uploads, Pest tests, and the deployment gotchas nobody warns you about.

1 month ago

Building Powerful Admin Panels with Laravel 12 and Filament v5: A Production Guide

Ship a real Filament v5 admin panel on Laravel 12 — Resources, RBAC with Spatie, multi-tenancy, custom widgets, and a deployment checklist for teams beyond hello-world.

2 months ago

Scaling Laravel 12 with Octane and FrankenPHP: A Production Performance Guide

Cut Laravel 12 latency by more than half with Octane and FrankenPHP — install, configure, audit singletons, and benchmark, with the production gotchas that bite teams in week two.

2 months ago