PostgreSQL 18: Features DB Engineers Should Watch
PostgreSQL 18 shipped in September 2025 and delivers the most fundamental change to PostgreSQL’s storage engine in its history: asynchronous I/O. This post was written in January 2025 based on accepted CommitFest patches and has been validated against the final PG18 release. All four features described below shipped as documented.
Situation
PostgreSQL has used synchronous I/O since its inception. Every read and write to storage blocks the backend process until the kernel returns. This is simple, predictable, and correct — but it means every disk-bound query is a sequence of blocking kernel calls with no opportunity for the backend to do useful work while waiting for I/O.
Modern storage — NVMe SSDs, io_uring-capable kernels, cloud block storage with significant parallelism — is well-suited to concurrent I/O. PostgreSQL could not take advantage of this without a fundamental change to how it submits and waits for I/O requests.
PG18 introduces asynchronous I/O as an optional mode. Alongside this, several replication and operational improvements address long-standing gaps. Operators who plan upgrades should understand these changes now, because some of them alter default behavior.
The Problem
The synchronous I/O model has a measurable impact on workloads that require high disk throughput: parallel queries hitting large tables, checkpoint writers under heavy write load, and logical replication subscribers applying changes from high-write publishers. Each backend process can only have one I/O operation in flight at a time.
The operational impact shows up as I/O utilization that looks low on aggregate metrics (storage is not at 100% IOPS) while query latency is high. The storage device has capacity, but PostgreSQL is not submitting enough concurrent requests to use it. This is the structural problem that asynchronous I/O in PG18 addresses.
The risk for operators: asynchronous I/O changes how PostgreSQL interacts with the kernel, which changes how it behaves on specific OS and storage configurations. Teams that upgrade to PG18 on non-standard storage setups (network block storage, certain cloud filesystems, shared storage) may observe different I/O patterns than they expect. How should engineering teams prepare their infrastructure for PostgreSQL 18’s new I/O and replication models?
Core Concept
flowchart TD
A["Client Query"] --> B["PG18 Backend Process"]
B --> C{"io_method GUC"}
C -->|"sync"| D["Blocking Kernel Calls"]
C -->|"worker"| E["Background Worker Threads"]
C -->|"io_uring"| F["Linux io_uring Non-blocking AIO"]
E --> G["Storage Engine"]
F --> G
D --> G
1. Asynchronous I/O (AIO)
PG18 introduces a framework for non-blocking I/O. On Linux with kernel 5.1 or newer, PostgreSQL can use io_uring as the AIO backend. On other platforms, it falls back to a worker-thread-based AIO implementation.
The GUC io_method controls the behavior:
sync— traditional synchronous I/O (always available, backward-compatible)worker— AIO using background worker threads (available on all platforms)io_uring— AIO using Linux io_uring (Linux 5.1 and newer; requires PostgreSQL built with--with-liburing)
The expected benefit is measurable on parallel sequential scans and checkpointing — workloads where multiple I/O operations can be queued concurrently.
2. Parallel streaming apply for logical replication
PG17 improved sequence replication. PG18 extends parallel apply by changing the default streaming option for CREATE SUBSCRIPTION from off to parallel. In PG16 and PG17, parallel streaming required explicit configuration. In PG18, new subscriptions stream large transactions in parallel by default.
The operational consequence: subscribers on PG18 will consume more CPU and hold more locks during apply than a comparable PG17 subscriber would. Conflict handling logic that assumes single-threaded apply ordering may behave differently with parallel apply enabled. The pg_stat_subscription_stats view provides per-subscription apply metrics including conflict counts, which is the right place to observe this.
3. pg_createsubscriber --all
PG18 adds --all to pg_createsubscriber, the tool for converting a physical standby into a logical replication subscriber. Before PG18, this required specifying individual databases or tables. With --all, the tool sets up logical replication for all databases on the standby in one command.
This simplifies the zero-downtime major version upgrade workflow significantly. The documented use case: take a physical streaming replica, convert it to a logical subscriber of the primary, let it catch up as a logical subscriber, then promote. The --all flag reduces the setup steps for multi-database clusters.
4. Improved conflict visibility in logical replication
Logical replication conflict handling in PG17 and earlier emitted minimal log information when a conflict occurred (a duplicate key or update to a row that was deleted on the subscriber). PG18 adds structured conflict detail to the log messages and extends pg_stat_subscription_stats with conflict type counts.
The operational impact: conflict-based apply failures are now diagnosable from log output without attaching debuggers or running manual queries. The new log format changes what conflict monitoring tools expect to parse. Log aggregation pipelines that alert on replication conflict patterns need to update their regex or structured log parsers before upgrading to PG18.
In Practice
PostgreSQL 18’s AIO framework shipped with io_uring requiring both Linux kernel 5.1 or newer and a PostgreSQL build with --with-liburing. PostgreSQL’s behavior when falling back is well-defined: if the environment restricts io_uring at the container or hypervisor level — which is common in some managed cloud offerings — the system gracefully falls back to traditional modes. Database operators must test the specific io_method setting against their target storage environment.
For logical replication, PostgreSQL’s behavior with max_parallel_apply_workers_per_subscription is documented to change ordering guarantees. Within a single transaction, order is preserved, but across transactions, parallel workers may apply changes out of logical commit order. Applications that depend on subscribers seeing changes in strict commit order must account for this behavior change.
Where It Breaks
| Scenario | What breaks | Why |
|---|---|---|
| AIO on unsupported storage or kernel | io_uring mode falls back to worker mode, and expected I/O gains do not materialize | io_uring requires kernel 5.1 or newer and is blocked in some cloud managed environments |
| Parallel apply with existing conflict handling | Apply errors or stalled replication on rows processed out of expected order | Multi-worker apply does not guarantee cross-transaction ordering, so single-threaded conflict logic may not handle this correctly |
| Log parsing for replication conflict alerts | Alert rules that matched old conflict log format produce no alerts or false positives | PG18 structured conflict log messages use a different format than PG17 unstructured messages |
What to Do Next
- Problem: PG18’s AIO and default parallel apply change I/O behavior and replication ordering assumptions — upgrading without testing on representative workloads risks performance regressions and silent replication issues.
- Solution: Test PG18 with
io_method = workerfirst to establish broad platform compatibility, validate logical replication behavior with parallel apply enabled, and update conflict log parsing before production adoption. - Proof: On a PG18 test instance, run a parallel sequential scan against a large table with
io_method = workerand compare elapsed time against the same query on PG17 — the expected result is measurably faster for scans larger than shared buffers. - Action: If you run logical replication subscribers today, review
pg_stat_subscription_statson PG17 and establish a conflict count baseline — this is the metric to validate stays within expected range on PG18 after enabling parallel apply.