Skip to main content
Configure your publisher and subscriber for the tables and subscriptions you plan to replicate.

Choosing Publication and Subscription Boundaries

For large or high-churn production tables, use one publication and one subscription per large table, or group only small related tables together. This gives each subscription its own apply worker and replication slot. In normal steady-state replication, Postgres does not parallelize ordinary change application across tables within a single subscription, so one hot table can delay other tables that share that apply worker. A publication per table alone does not provide that isolation unless it also has its own subscription. If you split replication this way, allow enough slots and workers for all your subscriptions, including extra capacity during the initial copy. On the publisher:
  • max_replication_slots: Allow one slot per subscription, plus extra slots for table synchronization during bootstrap. With the default settings, each bootstrapping subscription can use up to two extra slots.
  • max_wal_senders: Allow enough senders for those replication slots, plus any physical replicas.
On the subscriber:
  • max_replication_slots and max_logical_replication_workers: Allow capacity for every subscription, plus extra capacity for table synchronization.
  • max_worker_processes: Allow enough processes for the logical replication workers and any other background workers.
  • On Postgres 18+, also size max_active_replication_origins for replication origin tracking.

Handling Tables Without Primary Keys

Postgres needs a replica identity to replicate UPDATE and DELETE operations. A primary key is best. Another suitable unique index can also be used as the replica identity. If a table has no suitable key, you can use the per-table fallback:
Do not think of this as a server-wide setting. REPLICA IDENTITY FULL is set per published table and should be treated as a fallback rather than the default design. Postgres explicitly warns that subscriber-side UPDATE and DELETE can become very inefficient under FULL, because the subscriber must locate the matching row using the entire old row image rather than a compact key. FULL also increases WAL volume and replication traffic on the publisher, since every UPDATE and DELETE writes the full before-image of the row into WAL instead of just the key columns.