← All articles
Fundamentals·9 min read

Logical vs Physical Replication: When to Use Each

By Remac Engineering·July 18, 2026

Logical vs Physical Replication: When to Use Each

PostgreSQL replicates data in two ways. Physical replication copies raw WAL bytes to a standby server, producing an identical copy of the entire database cluster. Logical replication decodes the WAL into row-level change events and delivers them selectively to a subscriber.

Both modes read the same Write-Ahead Log, but they consume it differently and serve different purposes. Physical replication is for high availability and disaster recovery. Logical replication is for selective table syncing, cross-version upgrades, and Change Data Capture.

Choosing between them depends on what you need. Many production setups run both.


Physical Replication

Physical replication streams the raw WAL bytes from a primary server to one or more standby servers. The standby replays these bytes into its own data files, maintaining a byte-level identical copy of the primary.

Physical replication streams raw WAL bytes to create an identical standby; logical replication decodes WAL into row-level events for selective delivery to subscribers or CDC destinations

How It Works

The primary writes WAL as part of normal operation. A WAL sender process streams those bytes over a replication connection to the standby's WAL receiver process. The standby writes the incoming bytes to its own pg_wal directory and replays them continuously through PostgreSQL's recovery mechanism.

Two streaming modes exist:

  • Asynchronous (default): The primary does not wait for the standby to confirm receipt. If the primary crashes before the standby has received the latest WAL, those transactions are lost on the standby.
  • Synchronous: The primary waits for the standby to confirm it has written (or flushed, or applied) the WAL before acknowledging the commit to the client. This guarantees zero data loss at the cost of added commit latency.

The standby is read-only. With hot_standby = on, clients can connect and run read queries, but all writes are prohibited. The PostgreSQL documentation is specific: INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, and even temporary tables are blocked. The transaction_read_only parameter is hardcoded to true during recovery.

What You Get

Identical standby. The standby is a byte-for-byte copy of the primary. Every database, table, index, sequence, and role is replicated.

Fast failover. If the primary goes down, promote the standby to primary. Recovery is limited to replaying any WAL the standby received but had not yet applied.

Point-in-time recovery. PITR is a WAL archiving capability, not a streaming replication feature. But because both operate on the physical WAL, they share the same infrastructure: a base backup plus continuous WAL archiving lets you restore to any point in time.

Simple configuration. No per-table setup. No publications or subscriptions. The standby replicates everything automatically. Requires wal_level = replica (the default).

What You Don't Get

Per-table control. Physical replication is all-or-nothing. You cannot select specific tables or databases. The entire cluster is replicated because the WAL operates at the storage level, not the table level.

Cross-version compatibility. The PostgreSQL documentation states that log shipping between servers running different major release levels is not possible. The hardware architecture must also match. Even minor version differences, while likely to work, are not formally supported.

Cross-platform delivery. The WAL bytes are opaque binary data meaningful only to the same PostgreSQL version. You cannot stream them to MySQL, Elasticsearch, or Kafka.

Writable standby. If you need a writable copy of the database, physical replication is the wrong tool.


Logical Replication

Logical replication decodes the WAL into row-level change events (INSERT, UPDATE, DELETE) and applies them to a subscriber. Instead of raw bytes, the subscriber receives structured operations: "insert this row into the orders table" or "update column status to 'shipped' for row 1001."

How It Works

On the publisher, the WAL is decoded by the built-in pgoutput output plugin into a stream of structured messages. A logical replication slot tracks the subscriber's position and prevents the database from discarding unread WAL segments.

A publication defines which tables and which operations to include:

CREATE PUBLICATION orders_pub FOR TABLE orders, order_items;

On the subscriber, a subscription connects to the publisher and starts receiving changes:

CREATE SUBSCRIPTION orders_sub
    CONNECTION 'host=primary dbname=mydb'
    PUBLICATION orders_pub;

When a subscription is first created, PostgreSQL automatically performs an initial table synchronization: it copies existing data using dedicated table synchronization workers, up to max_sync_workers_per_subscription (default: 2) tables concurrently. Once the copy finishes for each table, the worker catches up with any changes that occurred during the copy, then hands off to the normal replication stream.

Logical replication requires wal_level = logical on the publisher. For details on WAL levels and replication slots, see PostgreSQL WAL: How It Works.

What You Get

Per-table control. Publish specific tables. Subscribe to only the tables you need. Filter by operation type (INSERTs only, no DELETEs, and so on).

Cross-version compatibility. Logical replication works between different major PostgreSQL versions. This is one of its primary use cases: performing major version upgrades with minimal downtime by replicating to a subscriber running the new version, then switching over.

Cross-platform delivery. The decoded change events are not opaque binary data. External tools can consume them via the logical replication protocol. This is what makes logical decoding the foundation for CDC to non-PostgreSQL destinations: Kafka, Elasticsearch, S3, and other systems.

Multiple subscribers. The same publication can serve multiple subscribers, each consuming independently via its own replication slot.

Writable subscriber. Unlike a physical standby, a logical replication subscriber is a normal PostgreSQL database that accepts writes.

What You Don't Get

DDL replication. Schema changes are not replicated. If you add a column on the publisher, you must add it manually on the subscriber. The PostgreSQL documentation recommends applying additive schema changes to the subscriber first to avoid errors when new columns appear in replicated data.

Sequence synchronization. Sequence state is not replicated. The row data generated by sequences is replicated (the actual column values), but the sequence object itself still shows its start value on the subscriber. If you plan to promote the subscriber to a primary, you need to update sequences manually.

Full cluster copy. Logical replication operates at the table level. System catalogs, roles, permissions, extensions, and server configuration are not replicated.

PITR. WAL archiving (which enables point-in-time recovery) operates on the physical WAL and pairs naturally with physical replication. Logical replication does not participate in this mechanism. Archiving decoded change events and replaying them is possible through external tooling, but it is not a built-in PostgreSQL feature.

Large object replication. Large objects (those stored via PostgreSQL's large object API) are not replicated.


Comparison

PhysicalLogical
Replication unitEntire clusterSelected tables
Data formatRaw WAL bytesDecoded row-level events
Same major PG version requiredYesNo
Standby/subscriber is writableNoYes
Replicates DDLYesNo
Replicates sequencesYes (full cluster)Values only (not sequence state)
Cross-platform deliveryNoYes (via logical decoding)
PITR (via WAL archiving)YesNo
Per-table filteringNoYes
Read replica supportYes (hot standby)Yes (but not the typical use case)
Required wal_levelreplica (default)logical

Using Both Together

Physical and logical replication are not mutually exclusive. Many production deployments run both because they solve different problems.

A common setup: physical replication to a standby for high availability and disaster recovery, plus logical replication (often via a CDC tool) to stream changes to Kafka, a search index, or a data warehouse.

This works because both modes read the same WAL. Setting wal_level = logical (required for logical replication) includes everything that physical replication needs. The logical level is a superset of replica. A single primary can serve physical standbys and logical subscribers simultaneously.

The trade-off is WAL volume. wal_level = logical produces more WAL data than replica, particularly for UPDATE and DELETE operations on tables with REPLICA IDENTITY FULL. For most workloads, this overhead is modest. Whether it matters depends on your write volume and storage constraints, but the capability it enables (physical HA plus logical CDC from one primary) is why many production systems accept it.


Where to Go from Here

This article covers the trade-offs between PostgreSQL's two replication modes. The related articles in this series go deeper into specific mechanics:

  • PostgreSQL WAL: How It Works: WAL internals, segment files, checkpoints, and replication slots
  • The pgoutput Protocol: how PostgreSQL's logical decoding converts WAL records into structured change events
  • What is Change Data Capture: how log-based CDC builds on logical decoding
  • CDC Delivery Guarantees: at-least-once, exactly-once, and what happens on failure

For the broader picture of how replication fits into transaction log processing, see What is Transaction Log Processing.

We built Remac to work with PostgreSQL's logical decoding. Remac reads the WAL via pgoutput, preserves transaction boundaries, and delivers change events to Kafka, S3, Elasticsearch, PostgreSQL, and several other destinations. Remac also supports physical WAL archival for disaster recovery and point-in-time recovery, so both replication modes are handled from a single tool. Remac currently supports PostgreSQL, with MySQL, MongoDB, SQL Server, and Oracle on the roadmap.

Take a look at remac.io.


Further Reading:

PostgreSQLReplicationCDCDataEngineering

More from this volume

Deploy once. Forget the pipeline exists.

Your data arrives where it needs to be, in order, with delivery guarantees and your team never thinks about it again.

Read the docs