Streaming Replication: walsender and walreceiver
Streaming replication keeps a standby byte-for-byte identical to its primary by shipping the primary's WAL stream and replaying it continuously. Because it replays the same physical changes, the standby is an exact copy — same data files, same block contents — which is why it requires the same major version and architecture.
Grounded in the source
Where this comes from in postgres/postgres
Each citation was checked against the REL_17_STABLE branch: real file path, symbol present, exact line number. Follow any link to read the code.
Primary symbol: WalSndLoop · line 2831
The one thing to understand first
Streaming replication keeps a standby byte-for-byte identical to its primary by shipping the primary's WAL stream and replaying it continuously. Because it replays the same physical changes, the standby is an exact copy — same data files, same block contents — which is why it requires the same major version and architecture.
Physical replication is not "copying rows" — it is replaying the primary's recovery log on a second machine, forever. The standby is running the same crash-recovery code that runs after a restart, just never reaching the end.
The two key processes
- walsender (on the primary,
src/backend/replication/walsender.c) — a backend dedicated to one standby. It reads WAL and streams it over a replication connection. - walreceiver (on the standby,
walreceiver.c) — connects to the primary's walsender, receives the WAL stream, and writes it to the standby's WAL. - startup process (on the standby) — continuously replays the received WAL into the data files using the same recovery code used after a crash.
The flow of a change
- A transaction on the primary writes WAL records and flushes them at commit.
- walsender notices new WAL and streams it to each connected walreceiver.
- The standby's walreceiver writes the WAL locally and signals the startup process.
- The startup process replays the records, applying them to data pages.
- If the standby allows queries (hot standby), readers see the replayed state.
Setting it up
-- On the primary: a replication role and slot
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD '...';
SELECT pg_create_physical_replication_slot('standby1');
-- Build the standby from a base backup
pg_basebackup -h primary -U replicator -D /data -R --slot=standby1
-- -R writes the connection info; the standby starts in recovery and streams.Synchronous vs asynchronous
By default replication is asynchronous: the primary commits as soon as its own WAL is flushed, not waiting for the standby. This is fast but means a few recent transactions can be lost if the primary dies before the standby receives them. Synchronous replication (covered separately) makes the primary wait for standby confirmation, trading latency for zero data loss.
Layer 3 — Watch it happen on your own database
Lag is the distance between what the primary has written and what the standby has received/replayed, expressed as WAL LSNs:
-- On the primary
SELECT application_name, state,
pg_wal_lsn_diff(sent_lsn, write_lsn) AS write_lag_bytes,
pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag_bytes,
write_lag, flush_lag, replay_lag
FROM pg_stat_replication;replay_lag is what readers on the standby actually experience. Lag grows when the standby cannot replay as fast as the primary generates WAL (slow disk, single-threaded replay bottleneck, or recovery conflicts pausing replay). Watch state move through startup → catchup → streaming when a standby first connects, and watch the lag columns climb the moment the standby's disk can't keep up.
Layer 4 — The levers this hands you
The walsender/walreceiver core gives you a small set of high-stakes knobs:
- Replication slots prevent WAL loss. A physical replication slot makes the primary retain WAL until the standby has consumed it, so a briefly disconnected standby resumes without a fresh base backup. The mirror risk: a standby that stays down forever makes the primary retain WAL indefinitely and fill its disk — monitor
pg_replication_slotsfor slots far behind. - Synchronous vs asynchronous. Async (default) commits as soon as the primary's own WAL is flushed — fast, but a few recent transactions can be lost on primary failure. Synchronous makes the primary wait for standby confirmation — zero loss, higher latency.
- This is the foundation of HA. Streaming replication underpins read scaling (route reads to hot standbys), high availability (promote a standby on primary failure), and low-loss DR. Every HA tool — Patroni, repmgr, cloud managed failover — is orchestration on top of this walsender/walreceiver core.
Layer 5 — What an Oracle DBA should expect vs what they get
Streaming replication maps closely to Oracle Data Guard, but the moving parts have different names and trade-offs:
- Streaming replication ≈ Data Guard physical standby. The walsender/walreceiver pair plays the role of the Data Guard transport and apply services; WAL is the redo stream.
- Replication slots ≈ Data Guard's managed log retention, but with a sharp edge: there is no automatic cap, so an abandoned slot will fill the primary's disk — there is no built-in
RMAN-style safety net. - Synchronous replication ≈ Data Guard maximum availability/protection modes, chosen per-standby via
synchronous_standby_namesrather than a protection-mode setting. - No Active Data Guard licence needed. Hot standby (read queries on the standby) is built in and free — unlike Oracle, where reads on a physical standby require the separately licensed Active Data Guard.
Key takeaway
A standby is the primary's WAL replayed continuously by the startup process, fed by a walsender/walreceiver pair — making it an exact physical copy that must match the primary's major version. Use a replication slot to guarantee the primary keeps the WAL the standby needs (and monitor it so an abandoned standby doesn't fill the disk), choose async or synchronous by your loss tolerance, and remember every HA framework is just orchestration on top of this core.
Interview lens
How this shows up in interviews
What an interviewer is actually testing, the same mechanism seen from three roles, and the gap between a shallow answer and one that shows real depth.
What the interviewer is testing
Whether you understand physical replication mechanics (walsender/walreceiver, byte-identical replay) and its constraints.
Questions you should be able to answer
- ▸How does a standby stay in sync — what exactly is shipped and replayed?
- ▸Why must a physical standby match the primary's major version and architecture?
- ▸What's the difference between async and sync streaming?
Database engineer
You monitor replication lag via LSN positions (sent/write/flush/replay) in pg_stat_replication and provision standbys identically to the primary.
Software engineer
You know a physical standby is byte-identical and read-only, so it's for HA and read-scaling, not schema experiments.
Feature builder
You send read-only traffic to standbys knowing they replay the exact same blocks with some lag.
Shallow answer
'The standby copies the primary.' No walsender/walreceiver, no reason for the version/arch constraint.
Answer that shows depth
Streaming replication ships the primary's WAL stream: a walsender on the primary streams WAL records to a walreceiver on the standby, which writes and continuously replays them, keeping the standby byte-for-byte identical (same data files and block contents). Because it replays physical changes, primary and standby must share major version and CPU architecture. Lag is tracked as LSN positions (sent/write/flush/replay) in pg_stat_replication. It is asynchronous by default (the primary doesn't wait); synchronous mode makes commit wait for standby confirmation.
Pro lab notebook
The captured run behind every query
Every SQL query above is real and the source citations are verified. Pro unlocks the captured psql output — each query re-run against a real PostgreSQL 17.10 lab, with its verbatim result.
1 real lab transcript for this lesson
The explanation and the SQL above are free — so are the verified source citations. What Pro unlocks is the proof: every query in Streaming Replication: walsender and walreceiver re-run against a real PostgreSQL 17.10 instance, with its verbatim psql output captured line for line.
What Pro unlocks here
- Every query in this lesson re-run against a real PostgreSQL 17.10 lab
- The verbatim psql output — page headers, row versions, plan nodes, catalog rows
- The corrected form of any query the source lesson got wrong, re-captured
- A copy-ready notebook you can replay yourself to confirm every claim
How this was verified
This explanation is anchored to PostgreSQL's source tree — the files linked above, on the REL_17_STABLE branch — and cross-checked against the official documentation for versions 15 through 18. Every SQL query shown was executed and its output captured in a throwaway PostgreSQL 17.10 lab; where a query needed correcting to run, that correction is noted inline.
Official documentation: §27.2.5 Streaming Replication