WAL archiving is the mechanism that ships each completed write-ahead-log segment somewhere safe, so you have a continuous record to replay during PITR. archive_command runs on the live server to save segments; restore_command runs during recovery to fetch them back.
archive_command — the save side
Enable archiving and tell PostgreSQL how to copy a finished 16 MB WAL segment out of pg_wal/ to durable storage. PostgreSQL substitutes %p (the path to the segment) and %f (its filename).
# postgresql.conf (requires restart for wal_level)
wal_level = replica # 'replica' or 'logical' — not 'minimal'
archive_mode = on
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'
The test ! -f guard refuses to overwrite an existing file — important, because a silent overwrite corrupts your archive.
restore_command — the fetch side
During recovery, PostgreSQL calls restore_command to pull each segment back from the archive. As of PostgreSQL 12 it lives in postgresql.conf, paired with a recovery.signal file — there is no recovery.conf anymore.
# postgresql.conf on the recovering server
restore_command = 'cp /archive/%f %p'
It's the mirror image of archive_command: %f is the segment PostgreSQL wants, %p is where to place it.
Why a plain cp is the junior answer
cp to a local directory is fine for a demo and dangerous in production: no compression, no checksums, no off-host durability, no retention/expiry, and no parallelism. Two robust alternatives:
archive_commandto remote/object storage via a real tool (rsync over SSH,aws s3 cp, etc.).- Better, hand archiving to pgBackRest / WAL-G / Barman, which manage compression, encryption, integrity checks, retention, and parallel transfer for you.
archive_command = 'pgbackrest --stanza=main archive-push %p'