September 2025, Revisited: PostgreSQL 18 and the Quiet Rebuild of the I/O Stack
Eric Greene June 11, 2026This post is part of our Three-Year Retrospective series: thirty-six posts, one per month, looking back at what actually mattered in software engineering. This one covers September 2025.
On September 25, 2025, PostgreSQL 18 was released, and in a year dominated by AI announcements it was a reminder of what mature infrastructure engineering looks like: a fundamental rework of how the database talks to disk, shipped behind a configuration variable, with nothing breaking. While the industry argued about agents, the Postgres community quietly delivered the most significant performance-architecture change the project had made in years.
Async I/O: the headline that took a while to land
For its entire history, PostgreSQL had done synchronous I/O — issue a read, wait, proceed — and leaned on the operating system's read-ahead heuristics to hide the latency. PostgreSQL 18 introduced a real asynchronous I/O subsystem, controlled by the new io_method setting: worker (the cross-platform default, using dedicated I/O worker processes) and io_uring on Linux, which queues I/O through the kernel's modern async interface. Sequential scans, bitmap heap scans, and vacuum could now keep multiple reads in flight, and benchmarks showed up to 3x improvements in the right scenarios — most dramatically on cloud storage, where per-read latency is exactly the thing you want to overlap.
The practical guidance we gave in trainings that autumn: the win is workload-dependent, so benchmark your workload; worker is a sensible default; and io_uring is worth testing on Linux hosts where vacuum and large scans dominate. Reports through late 2025 bore this out — unremarkable on fast local NVMe, transformative on network-attached storage.
The features developers actually touched first
Async I/O was the architectural story, but three smaller features got used on day one.
uuidv7() ended one of the longest-running arguments in schema design. UUIDv4 primary keys are write-scattering, index-bloating randomness; sequential integers leak information and complicate merges. UUIDv7 — timestamp-ordered, globally unique — gives you index locality and uniqueness at once, and having it native in the database (rather than via an extension or application code) made it the easy default for new tables practically overnight.
OLD and NEW in RETURNING quietly removed a whole category of round-trips. UPDATE ... RETURNING old.balance, new.balance gives you before-and-after in a single statement, for INSERT, UPDATE, DELETE, and MERGE. Audit logging, optimistic-concurrency checks, and "what did I just change?" APIs all got simpler. Together with uuidv7(), the new-table boilerplate of 2025 looked like this:
CREATE TABLE accounts (
id uuid PRIMARY KEY DEFAULT uuidv7(),
balance numeric NOT NULL
);
UPDATE accounts
SET balance = balance - 50.00
WHERE id = $1
RETURNING old.balance AS balance_before,
new.balance AS balance_after;OAuth 2.0 authentication mattered most to platform teams: a new oauth method in pg_hba.conf, with pluggable token validators, meant Postgres could finally participate directly in an organization's single-sign-on story instead of bolting identity on through middleware or LDAP adapters.
The release also made pg_upgrade retain planner statistics — minor-sounding, but it eliminated the post-upgrade performance crater that had made teams dread major-version upgrades, which is the kind of fix that changes behavior more than any feature does.
The release as a teaching moment
PostgreSQL 18 became our standing example of how to evolve a critical system. The async I/O work had been landing in pieces across multiple releases, invisible until the architecture was ready. The new behavior shipped configurable rather than forced. The features answered real, boring, persistent pain — UUID index bloat, upgrade statistics, SSO integration — rather than chasing a trend. There is a reason Postgres kept extending its lead as the default database of new applications through 2025 and 2026, and September 2025 is a one-release summary of that reason.
Looking back from June 2026
Nine months on, PostgreSQL 18 adoption followed the usual Postgres curve — cautious through the x.1 and x.2 minors, then broad. uuidv7() is already the unremarkable default in new schemas we see, async I/O has proven its value mostly in cloud deployments exactly as expected, and the OAuth support is showing up in enterprise architecture diagrams. Nothing about the release looks different from June 2026 than it did in September 2025, and for database infrastructure, that predictability is the highest compliment available.
If your team runs Postgres in production, PostgreSQL for Administrators covers the 18-era operational surface — io_method tuning, upgrade planning, and authentication configuration included — and PostgreSQL for Python Programmers puts uuidv7 keys, RETURNING patterns, and modern Postgres features to work from application code.