Just a few weeks ago I published a blog posting about the new features of SQL Server 2025, exploring where Microsoft is taking its flagship database engine. Today, I want to continue in the same spirit – but this time from the PostgreSQL side of the world. PostgreSQL 18 was released just last week, and as always, the open-source community has delivered an impressive set of enhancements that are worth careful examination. In this post, I’ll walk you through the highlights, show examples of how they can be applied, and link to the official documentation so you can explore the details yourself.

Performance & Internals
The first time I flipped the io_method setting and watched the view pg_aios come alive, I realized PostgreSQL 18 was not holding back. The new asynchronous I/O subsystem allows backends to queue multiple read requests concurrently, which makes sequential scans, bitmap heap scans, and even VACUUM operations much more efficient.
On one test machine with a 2 billion-row table, switching to io_method = ‘worker’ (or io_method = ‘io_uring’ when available) cut query latency significantly. With many overlapping I/O requests, the backend stays busy even while waiting on disk reads. The pg_aios view surfaces which file handles are being tracked in the AIO queue.
Another internal shift is in index handling. PostgreSQL 18 now supports skip scans on multicolumn B-Tree indexes. Suppose you have an index on (last_name, first_name). Previously, queries filtering only on first_name would bypass the index and fall back to sequential scan. Now:
SELECT * FROM person WHERE first_name = 'Klaus';
can still leverage the B-Tree index by “skipping” through the ranges of last_name values. The planner uses ordering information to avoid scanning irrelevant spans.
Parallel GIN index builds also arrive in this version, helping accelerate index creation on JSONB or full-text workloads.
SQL Features & Developer Experience
While performance is often the headline grabber, PostgreSQL 18 also extends expressiveness in surprising ways. One of my favorite features is the support for virtual generated columns. In prior versions, generated columns had to be stored (i.e. computed and materialized). Version 18 introduces virtual (on-read) generated columns that do not consume disk storage but behave just like normal columns at query time.
ALTER TABLE orders
ADD COLUMN gross_total numeric GENERATED ALWAYS AS (net_total * (1 + vat_rate)) VIRTUAL;
The column gross_total is never stored, but it joins, projects, and replicates just like any other column. It’s especially useful when many derived values exist and you don’t want redundant storage.
PostgreSQL 18 also ventures deeper into the realm of temporal constraints. You can now declare PRIMARY KEY or UNIQUE constraints that forbid overlapping time ranges via the WITHOUT OVERLAPS clause, and likewise use FOREIGN KEY … PERIOD to refer to periods.
CREATE TABLE contracts (
id bigint,
valid tstzrange NOT NULL,
PRIMARY KEY (id) WITHOUT OVERLAPS
);
This enforces that no two rows with the same id can have overlapping valid periods. It’s a powerful way to bake time-based business logic into your data model.
Another small but delightful addition is the enhancement to RETURNING clauses: you can now refer to both OLD and NEW row versions in INSERT, UPDATE, DELETE, and MERGE. That means you can do transformations and audit logging all in one shot.
And for ID generation, there’s uuidv7(), which produces time-ordered UUIDs that combine uniqueness with index-friendliness. The PostgreSQL docs for UUID types cover this new function.
Operations, Security & Observability
Upgrades used to carry the dread of “cold start performance” – immediately after migrating, you’d have to re-analyze every table, and often query plans would misbehave. PostgreSQL 18 addresses this: pg_upgrade now preserves optimizer statistics. That means after an upgrade, your cluster doesn’t start from zero, and your queries don’t suffer the usual performance cliff.
On the security and integrity side, data checksums are now enabled by default when you initdb, protecting against silent corruption. You can, of course, disable it via –no-data-checksums if needed.
Also, PostgreSQL 18 marks MD5 password authentication as deprecated, nudging users toward SCRAM or more modern methods. It also adds support for OAuth 2.0 authentication – useful for integrating with identity providers.
Observability and diagnostics get their share of love. EXPLAIN ANALYZE now automatically includes buffer usage (BUFFERS) without needing extra options. In verbose mode, you also get CPU, WAL, and average-read statistics plus index lookup counts.
Logging improvements also arrive: log_lock_failures, finer placeholders like %L (client IP) in log_line_prefix, and better replication conflict reporting.
Summary
As I walked through the internals of PostgreSQL 18, explored new indexing strategies, reformulated schema designs, and measured query performance before and after, one thing became clear: this release isn’t just “more of the same.” It is an invitation to rethink how we model time, how we expect upgrades to behave, and how much the database itself can do internally on our behalf.
Performance gets a new engine (AIO), expressiveness gets new levers (virtual columns, temporal constraints, improved RETURNING), and operations get fewer friction points (stats preservation, default checksums, OAuth). Each feature links into a bigger narrative about making PostgreSQL smarter and more resilient.
Thanks for your time,
-Klaus