From two blank machines
to a working primary + replica.
The replication demo showed you what a leader and follower do conceptually. This page is the other half: the actual commands and config files that turn two real (or containerized) Postgres servers into that setup — in order, with the reason for each step.
The setup, step by step
Click a step below. The diagram highlights exactly what changes on which machine, and the panel shows the real command or config for it.
Before you do this for real
The 7 steps get you a working replica. These three decisions determine whether it survives production.
Sync vs. async replication pick one
By default this setup is asynchronous — the primary commits and returns to the client without waiting for the replica to confirm it received the WAL. Fast, but a crash right after commit can lose the last few transactions. Toggle it below.
Async (default): synchronous_standby_names is unset. The primary never blocks on a replica — fastest writes, but failover can lose the most recent commits.
Failover not automatic
Nothing in this setup promotes the replica automatically if the primary dies. Manually, it's one command on the replica: pg_ctl promote — that stops it replaying WAL and starts accepting writes.
For automatic failover you need something watching both nodes and re-pointing traffic: Patroni or repmgr if self-hosting, or a managed service (RDS, Cloud SQL, Aurora) if you'd rather not build that yourself.
Try it locally first — Docker Compose
Fastest way to see the whole thing work end-to-end without provisioning real machines: two containers on one Docker network, doing exactly the 7 steps above automatically on startup. Local testing only — the replica's entrypoint script and open trust auth are not production-safe.
version: "3.8"
services:
primary:
image: postgres:16
container_name: pg-primary
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: appdb
command: >
postgres -c wal_level=replica -c max_wal_senders=10
-c max_replication_slots=10 -c hot_standby=on
volumes:
- ./primary-data:/var/lib/postgresql/data
- ./init-primary.sql:/docker-entrypoint-initdb.d/init-primary.sql
ports: ["5432:5432"]
networks: [pgnet]
replica:
image: postgres:16
container_name: pg-replica
depends_on: [primary]
environment:
PGPASSWORD: strongpassword
entrypoint: >
bash -c "
until pg_isready -h primary -U replicator; do sleep 1; done;
rm -rf /var/lib/postgresql/data/*;
pg_basebackup -h primary -U replicator -D /var/lib/postgresql/data
-Fp -Xs -P -R --slot=replica_01_slot;
chmod 700 /var/lib/postgresql/data;
exec docker-entrypoint.sh postgres"
volumes:
- ./replica-data:/var/lib/postgresql/data
ports: ["5433:5432"]
networks: [pgnet]
networks:
pgnet: {}
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'strongpassword';
-- open pg_hba.conf trust for the docker subnet so the replica container can connect;
-- for anything beyond a local test, scope this to the replica's IP and use scram-sha-256.
SELECT pg_create_physical_replication_slot('replica_01_slot');
docker compose up -d
docker exec -it pg-primary psql -U postgres -c "SELECT client_addr, state FROM pg_stat_replication;"
docker exec -it pg-replica psql -U postgres -c "SELECT pg_is_in_recovery();"
Same two checks as step 7 — if the first returns a row with state = streaming and the second returns t, replication is live.
Command cheat sheet
Same 7 steps, compressed to one line each.
| # | Where | Command / file |
|---|---|---|
| 1 | Primary | CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD '…'; |
| 2 | Primary | pg_hba.conf — add host replication replicator <replica_ip>/32 scram-sha-256 |
| 3 | Primary | postgresql.conf — wal_level=replica, max_wal_senders, max_replication_slots, restart |
| 4 | Primary | SELECT pg_create_physical_replication_slot('replica_01_slot'); |
| 5 | Replica | pg_basebackup -h <primary> -U replicator -D <datadir> -Fp -Xs -P -R --slot=replica_01_slot |
| 6 | Replica | start Postgres — standby.signal puts it into standby mode automatically |
| 7 | Both | SELECT * FROM pg_stat_replication; (primary) / SELECT pg_is_in_recovery(); (replica) |