Home Blog PostgreSQL 17 new features MERGE and log Database Deep Dives
PostgreSQL 17 new features MERGE and log February 17, 2026 9 min read

Database Deep Dives

PostgreSQL 17 new features MERGE and log Enterprise Guide 2026 SCALE D2C D2C Technology PostgreSQL 17 new features MERGE and log Enterprise Guide 2026 SCALE D2C D2C Technology

PostgreSQL 17, released in September 2024, delivers significant improvements to MERGE statement capabilities, logical replication, performance, and JSON handling. For engineering teams running PostgreSQL in production, understanding what changed — and how to leverage it — is essential for 2026 planning.

PostgreSQL 17: What Changed and Why It Matters

PostgreSQL 17 is a major release that continues the project's tradition of significant feature additions alongside robust performance improvements. The headline features for enterprise engineering teams are the expanded MERGE statement (now with RETURNING clause and unconditional WHEN NOT MATCHED BY SOURCE), major logical replication enhancements (including replication slot failover), a new streaming I/O subsystem, and improvements to VACUUM and query planning.

Faster sequential scans with the new streaming I/O subsystem
30%
Reduction in VACUUM overhead on high-update tables
Sep 2024
GA release date; PostgreSQL 18 in development for 2025

MERGE Enhancements in PostgreSQL 17

The SQL MERGE statement (ISO/IEC 9075-2:2003) was added to PostgreSQL in version 15 but had significant limitations compared to the standard. PostgreSQL 17 closes most of those gaps with two major additions: MERGE ... RETURNING and WHEN NOT MATCHED BY SOURCE.

MERGE ... RETURNING

PostgreSQL 17 allows MERGE statements to return rows affected by the operation, similar to how INSERT, UPDATE, and DELETE support RETURNING. This is extremely useful for audit logging, returning generated IDs, and pipeline processing:

MERGE INTO customers AS target
USING staging_customers AS source
ON target.customer_id = source.customer_id
WHEN MATCHED THEN
  UPDATE SET
    email = source.email,
    updated_at = NOW()
WHEN NOT MATCHED THEN
  INSERT (customer_id, email, created_at)
  VALUES (source.customer_id, source.email, NOW())
RETURNING merge_action(), target.customer_id, target.email;

The merge_action() function (new in PostgreSQL 17) returns 'INSERT', 'UPDATE', or 'DELETE' for each row processed, enabling precise audit trail construction without additional queries.

WHEN NOT MATCHED BY SOURCE

This clause, finally added in PostgreSQL 17, allows MERGE to handle rows in the target table that have no corresponding row in the source — enabling true UPSERT-and-delete patterns in a single statement:

MERGE INTO products AS target
USING latest_product_feed AS source
ON target.sku = source.sku
WHEN MATCHED AND source.active = TRUE THEN
  UPDATE SET price = source.price, stock = source.stock
WHEN MATCHED AND source.active = FALSE THEN
  DELETE
WHEN NOT MATCHED BY TARGET THEN
  INSERT (sku, price, stock) VALUES (source.sku, source.price, source.stock)
WHEN NOT MATCHED BY SOURCE THEN
  -- Row exists in products but not in feed: mark as discontinued
  UPDATE SET discontinued = TRUE, updated_at = NOW();

This capability was previously only available in SQL Server and enabled complex ETL operations in a single atomic transaction — something PostgreSQL users had to implement with multiple CTE statements and subqueries.

Logical Replication Improvements

Logical replication is a critical capability for PostgreSQL architectures requiring zero-downtime major version upgrades, selective table replication, and change data capture (CDC) pipelines. PostgreSQL 17 delivers several important improvements:

🔄
Replication Slot Failover
Logical replication slots can now be synced to standby servers and automatically failed over during a primary promotion. Previously, logical replication slots were lost during failover, breaking all downstream consumers and requiring manual reconnection.
Faster Initial Table Sync
Initial table synchronisation for new subscribers is significantly faster in PostgreSQL 17 due to improved parallel copy operations. Large tables that previously took hours to sync now complete in a fraction of the time.
🔌
Disconnected Slot Behaviour
Improved handling of inactive replication slots, with better WAL retention management to prevent disk exhaustion when a subscriber goes offline for an extended period.
📋
Replication of DDL (Limited)
While full DDL replication is still not available in core PostgreSQL, v17 improves handling of schema changes for replicated tables, reducing cases where schema changes break logical replication subscriptions.
💡 Why Replication Slot Failover Matters

Before PostgreSQL 17, logical replication slots were a primary reason teams hesitated to use logical replication in high-availability setups. A primary failure meant all downstream CDC consumers (Debezium, Kafka Connect, read replicas for reporting) would lose their position in the WAL stream and require manual reconnection or replay. Replication slot failover eliminates this pain for HA deployments.

Performance: Streaming I/O and VACUUM

PostgreSQL 17 introduces a new streaming I/O subsystem that significantly improves performance for sequential workloads — full table scans, VACUUM operations, and bulk data loads. The new system uses asynchronous I/O under the hood (via io_uring on Linux, and asynchronous reads on other platforms) to pipeline I/O operations, reducing the time that sequential scans spend waiting for disk.

OperationPostgreSQL 16PostgreSQL 17Improvement
Sequential Scan (large table)Baseline~2× fasterStreaming I/O prefetch
VACUUM (large table)Baseline~20–30% fasterImproved dead tuple tracking
COPY (bulk load)Baseline~15% fasterStreaming I/O write path
CREATE INDEX CONCURRENTLYBaselineMarginal improvementLimited impact (CPU bound)
Hash Join (large datasets)Baseline~10–15% fasterImproved hash table memory mgmt

VACUUM performance improvements in v17 are particularly valuable for high-write OLTP workloads. The new dead tuple tracking algorithm reduces the WAL written during VACUUM operations and improves the efficiency of visibility map updates, resulting in lower I/O overhead during autovacuum cycles.

JSON and SQL/JSON Improvements

PostgreSQL 17 continues to close the gap between PostgreSQL's JSON capabilities and the SQL/JSON standard (ISO/IEC 9075-2:2016). New in v17:

  • JSON_TABLE() — Convert JSON data to relational rows/columns using JSON path expressions, similar to XMLTable. Useful for querying API responses and semi-structured data stored in JSONB columns.
  • SQL/JSON constructor functionsJSON(), JSON_SCALAR(), JSON_SERIALIZE() for standards-compliant JSON construction.
  • SQL/JSON query functionsJSON_EXISTS(), JSON_VALUE(), JSON_QUERY() as alternatives to PostgreSQL's @> and ->> operators, improving portability across database platforms.
-- Using JSON_TABLE to query nested JSON arrays
SELECT jt.order_id, jt.item_name, jt.quantity
FROM orders,
JSON_TABLE(
  order_data,
  '$.items[*]' COLUMNS (
    order_id FOR ORDINALITY,
    item_name TEXT PATH '$.name',
    quantity INT PATH '$.qty'
  )
) AS jt
WHERE jt.quantity > 5;

Upgrade and Migration Guidance

01
Review Breaking Changes
PostgreSQL 17 has a small set of breaking changes. Key ones: changes to how to_char() handles some format strings; removal of the --no-sync option from some utilities; and changes to COPY CSV handling of quoted empty strings. Review the full release notes before upgrading.
02
Test Logical Replication Failover
If you plan to use the new replication slot failover feature, test it thoroughly in staging. Both primary and standby must be on PostgreSQL 17. Slots must be created with failover = true to participate in failover sync.
03
pg_upgrade for Major Version Upgrades
Use pg_upgrade --link for near-zero downtime major version upgrades on most workloads. For logical replication scenarios, the new slot failover capability means you can now use logical replication for zero-downtime major version upgrades more reliably than before.
04
Review autovacuum Settings
After upgrading, review autovacuum settings — the improved VACUUM performance in v17 may allow you to tune autovacuum more aggressively (more frequent, lower thresholds) without significant I/O impact, improving table bloat management.

Frequently Asked Questions

The most impactful new features in PostgreSQL 17 are: the enhanced MERGE statement with RETURNING clause and WHEN NOT MATCHED BY SOURCE (enabling complex upsert-and-delete patterns in a single atomic operation); logical replication slot failover (eliminating a major reliability pain point for HA deployments); the new streaming I/O subsystem delivering ~2× faster sequential scans; VACUUM performance improvements of 20–30%; and expanded SQL/JSON support including JSON_TABLE() and standard SQL/JSON constructor and query functions.

MERGE ... RETURNING allows you to return rows and columns from rows processed by a MERGE statement, similar to how INSERT/UPDATE/DELETE support RETURNING. It also adds the merge_action() function that returns the action performed on each row ('INSERT', 'UPDATE', or 'DELETE'). This enables audit logging, returning generated IDs from inserts, and pipeline processing without additional queries — all in a single atomic SQL statement.

WHEN NOT MATCHED BY SOURCE is a new MERGE clause in PostgreSQL 17 that handles rows in the target table that have no corresponding row in the source. Previously, MERGE only handled rows that existed in both tables (MATCHED) or only in the source (NOT MATCHED). The new clause allows you to take action (UPDATE or DELETE) on target rows that are absent from the source, enabling true full-sync patterns — for example, marking products as discontinued when they disappear from a product feed — in a single atomic statement.

Logical replication slot failover is the ability for replication slots to be synced to standby servers and automatically transferred to the new primary during a failover event. Before PostgreSQL 17, logical replication slots only existed on the primary — when the primary failed, all downstream consumers lost their position in the WAL stream and required manual reconnection or replay from scratch. This was a major reliability issue for CDC pipelines using tools like Debezium. With PostgreSQL 17, slots created with failover = true are synced to standbys and survive primary failover automatically.

Sequential scan performance improves by approximately 2× on workloads that can benefit from the new streaming I/O subsystem's prefetching. VACUUM operations on high-update tables are 20–30% faster. COPY bulk loads see ~15% improvement. Hash joins on large datasets improve by 10–15%. These improvements are most pronounced on I/O-bound workloads and systems with fast NVMe storage. CPU-bound workloads see smaller improvements. Individual results vary significantly by workload, hardware, and data patterns.

JSON_TABLE() is a new SQL function that converts JSON data into a relational result set using JSON path expressions. It allows you to query JSONB columns containing arrays or nested objects as if they were rows and columns, without needing custom application-level JSON parsing. It follows the SQL/JSON standard (ISO/IEC 9075-2:2016) and works similarly to Oracle and SQL Server's JSON_TABLE implementations, improving portability for teams working across multiple database platforms.

The standard upgrade path for major version upgrades is pg_upgrade. Use pg_upgrade --link for near-zero downtime on most workloads by hard-linking data files rather than copying them. Test the upgrade in staging first and review the full release notes for breaking changes. For Kubernetes deployments, operators like CloudNativePG and Zalando Postgres Operator support in-place major version upgrades. Managed services (AWS RDS, Google Cloud SQL, Azure Database for PostgreSQL) typically support PostgreSQL 17 upgrades via their standard version upgrade workflows.

For most production workloads, upgrading to PostgreSQL 17 is worthwhile, especially if you use logical replication (slot failover is a significant reliability improvement), have I/O-bound workloads (streaming I/O improvements), or want the improved MERGE capabilities for ETL pipelines. PostgreSQL 15 reaches end of life in November 2027 and PostgreSQL 16 in November 2028, so there is no urgency from an EOL perspective yet. That said, upgrading in advance of EOL during a non-critical period is better than rushing it under deadline pressure.

DATABASE D

Ready to Implement Database Deep Dives?

Our specialist team delivers measurable ROI from PostgreSQL 17 new features MERGE and log programmes for enterprise and D2C brands.

Free Audit