Backup & Recovery
How to protect your data against hardware failure, accidental deletes, and disasters — and how to get it back when the worst happens.
pg_dump — Logical Backups
Export your database as SQL or a custom archive
What is pg_dump?
pg_dump is PostgreSQL's built-in tool to export a database into a file you can restore later. It produces a logical backup — SQL statements or a binary archive that recreates your schema and data.
Full Backup — All Output Formats
pg_dump supports four output formats. The custom format (-Fc) is the most flexible and is recommended for most cases.
Schema-Only Backup
Sometimes you want only the structure (tables, indexes, functions) without any data — useful for setting up a new environment or migrations.
Restoring with pg_restore
Use pg_restore for custom/directory/tar backups. For plain SQL, use psql.
Automating Backups with a Shell Script
In production you always automate backups on a schedule (cron job).
PITR — Point In Time Recovery
"Undo" any mistake by rewinding to any moment in the past
What is PITR and Why Does It Exist?
pg_dump gives you a snapshot of a specific moment. But what if someone ran DELETE FROM orders; at 3:47 PM and you don't notice until 4:30 PM? Your last nightly backup was at 2 AM — you'd lose 13+ hours of data.
PITR (Point In Time Recovery) solves this. By continuously archiving WAL files, you can restore your database to any second in the past — not just backup times.
How PITR Works — The Big Picture
Step 1: Enable WAL Archiving
WAL archiving tells PostgreSQL to copy each completed WAL segment to a safe location (S3, NFS, another server) before recycling it.
archive_timeout = 60, you can lose at most 60 seconds of data. Set it lower for more critical data. The tradeoff is more archive storage used.Step 2: Take a Base Backup
A base backup is the starting point. PITR replays WAL on top of this base backup. You need a fresh base backup regularly (daily is common).
Step 3: Perform Point In Time Recovery
When disaster strikes, this is how you recover to a specific moment:
SELECT pg_wal_replay_resume(); to complete recovery.
Recovery Target Options
You can recover to different types of targets — not just a timestamp.
| Target Type | Setting | Example |
|---|---|---|
| Specific timestamp | recovery_target_time |
'2024-01-15 15:47:21 UTC' |
| Specific transaction ID | recovery_target_xid |
'1234567' — stop just before this txn |
| Named restore point | recovery_target_name |
'before_migration' |
| Specific LSN | recovery_target_lsn |
'0/4A000028' |
| Latest possible | recovery_target = 'immediate' |
Stop as soon as consistent (fastest) |
pg_create_restore_point('before_<migration_name>') before running major schema migrations in production. It gives you a clean rollback target if something goes wrong.WAL Recovery
How PostgreSQL auto-heals after a crash
Crash Recovery vs Point-in-Time Recovery
These are two different things that both use WAL:
What: Postgres crashed mid-write
(power outage, OOM kill, etc.)
How: On next startup, PostgreSQL
reads WAL and replays any
committed transactions that
didn't make it to data files.
You do: Nothing. Automatic.
Time: Seconds to minutes.
Goal: Consistency — no partial
transactions on disk.
What: Human error, logical corruption
(accidental DELETE, DROP TABLE)
How: You restore a base backup +
replay archived WAL files
to a specific moment.
You do: Everything (as above).
Time: Minutes to hours.
Goal: Roll back to a point BEFORE
the mistake was made.
What Happens During Crash Recovery
When PostgreSQL starts after a crash, it automatically goes through a recovery sequence:
pg_control) to find the most recent checkpoint LSN — this is the safe starting point.
WAL Archiving Tools for Production
Writing your own archiving scripts works, but these battle-tested tools are preferred in production:
| Tool | What it does | Used by |
|---|---|---|
| pgBackRest | Full backup solution: base backup, WAL archiving, PITR, compression, S3/GCS/Azure support, parallel restore | Most production setups — Recommended |
| Barman | Backup and Recovery Manager by 2ndQuadrant. Good UI, streaming + archiving support, retention policies | Enterprise PostgreSQL setups |
| WAL-G | Lightweight Go tool for WAL archiving to cloud storage (S3, GCS, Azure). Used by Heroku Postgres. | Cloud-native setups |
| pg_dump (cron) | Simple logical backups on a schedule. Easy but no PITR. | Small apps, development No PITR |
Backup Strategy Builder
Get the right backup plan for your scenario
What Backup Do You Need?
🛡️ Backup Strategy Advisor Interactive
Backup Method Comparison
| Method | Granularity | PITR? | Speed | Best for |
|---|---|---|---|---|
pg_dump |
Database / table | No | Slow for large DBs | Small DBs, dev, schema migrations |
pg_basebackup only |
Full cluster | No | Fast (file copy) | Replication setup, base for PITR |
| pg_basebackup + WAL archive | Full cluster | Yes | Fast restore | Production — most common |
| pgBackRest | Full cluster + incremental | Yes | Fastest (parallel) | Large production DBs |
| Managed cloud (RDS, Supabase) | Full cluster | Yes | Managed for you | Cloud-hosted apps — easiest |
Backup Golden Rules & Testing
A backup you haven't tested is not a backup
The 3-2-1 Backup Rule
Industry standard for reliable backups:
Always Test Your Restores
Production Checklist
| Task | Frequency | Why |
|---|---|---|
| pg_dump (logical backup) | Daily | Table-level recovery, cross-version portability |
| pg_basebackup (full) | Daily or weekly | PITR starting point |
| WAL archiving | Continuous | PITR between backups |
| Test restore | Monthly | Verify backups actually work |
| Verify archive_command success | Daily alert | Detect silent failures |
| Check backup storage size | Weekly | Avoid running out of space |
| Rotate old backups | Per retention policy | Cost control |
-Fc format. Restores with pg_restore. No PITR.pg_basebackup copies the entire cluster. Foundation for PITR. Use -R flag for replica or -Ft -z for compressed archive.archive_mode=on, archive_command, restore_command.