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
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.
are where most apps feel the database — and 18 targets them hard
Should you upgrade?
New projects
Start on 18. You get uuidv7(), async I/O, and virtual generated columns from day one with no migration cost.
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.
Write-heavy apps using UUID keys
Migrating new tables to uuidv7() can reduce index bloat and improve insert performance as you grow.
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.
Comments
0No comments yet. Be the first to share your thoughts.