Database Backup Types: Full, Incremental, Differential, WAL Archiving
Database Backup Types: Full, Incremental, Differential, WAL Archiving
No database backup strategy is complete until it has been tested with a real restoration. This article covers backup types, PostgreSQL-specific tools, and how to implement point-in-time recovery (PITR).
Backup Types
Full Backup
A full backup copies the entire database cluster. It is the foundation of any backup strategy.
# PostgreSQL full backup with pg_dump (logical)
pg_dump -h localhost -U admin -Fc -f prod_backup.dump proddb
# Or directory format for parallel dumps
pg_dump -h localhost -U admin -Fd -j 4 -f /backups/proddb proddb
# Physical full backup with pg_basebackup
pg_basebackup -h localhost -U replicator \
-D /backups/full/$(date +%Y%m%d) \
-X stream -P -v
**Pros**: Complete snapshot, simple restoration. **Cons**: Large, time-consuming, resource-intensive.
Incremental Backup
An incremental backup captures only changes since the last backup (of any type). PostgreSQL achieves this via WAL archiving:
# Archive WAL segments continuously
# In postgresql.conf:
archive_mode = on
archive_command = 'cp %p /backups/wal/%f'
Each 16 MB WAL segment is an incremental backup.
Differential Backup
A differential backup captures changes since the last full backup. It is larger than an incremental but faster to restore (only the full + one differential needed).
-- pgBackRest differential backup
pgbackrest --stanza=prod --type=diff backup
WAL Archiving and Point-in-Time Recovery
WAL archiving is PostgreSQL's mechanism for continuous archiving. Combined with a base backup, it enables restoring to any point in time.
Configuration
# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'aws s3 cp %p s3://my-backups/wal/%f'
archive_timeout = 60
Recovery
To restore to a specific point in time:
# recovery.signal (or standby.signal for replica)
restore_command = 'aws s3 cp s3://my-backups/wal/%f %p'
recovery_target_time = '2026-05-10 14:30:00 UTC'
recovery_target_action = promote
Start PostgreSQL. It replays WAL segments until it reaches the target time and then promotes itself to a primary.
Complete PITR Workflow
# 1. Take a base backup
pg_basebackup -h prod-db -U replicator -D /backups/base_20260512 -X stream
# 2. Archive WAL continuously (configured in postgresql.conf)
# 3. Restore to a point in time
mkdir /var/lib/postgresql/restored
cp -r /backups/base_20260512/* /var/lib/postgresql/restored/
touch /var/lib/postgresql/restored/recovery.signal
cat > /var/lib/postgresql/restored/postgresql.conf << EOF
restore_command = 'aws s3 cp s3://my-backups/wal/%f %p'
recovery_target_time = '2026-05-12 03:15:00 UTC'
recovery_target_action = promote
EOF
pg_ctl start -D /var/lib/postgresql/restored
Backup Strategies Compared
| Type | Size | Restore Speed | Complexity | Frequency | |------|------|---------------|------------|-----------| | Full | Largest | Slowest | Low | Weekly | | Incremental | Smallest | Slowest | Medium | Continuous | | Differential | Medium | Medium | Medium | Daily | | WAL archiving | Tiny per segment | Fast (with base) | High | Continuous |
pg_dump vs pg_basebackup
Use `pg_dump` for:
* Logical backup of specific databases or schemas.
* Porting to a different PostgreSQL version or architecture.
* Selective restoration (single table or schema).
Use `pg_basebackup` for:
* Full-cluster physical backup.
* Setting up streaming replicas.
* Point-in-time recovery capability.
* Faster bulk restore (skip SQL parsing).
pgBackRest
pgBackRest is the most popular dedicated backup tool for PostgreSQL:
# Configure stanza
pgbackrest --stanza=prod stanza-create
# Full backup
pgbackrest --stanza=prod --type=full backup
# Incremental backup (default)
pgbackrest --stanza=prod --type=incr backup
# List backups
pgbackrest --stanza=prod info
# Restore to specific point
pgbackrest --stanza=prod --type=time \
--target="2026-05-12 03:15:00" restore
Testing Backups
A backup that cannot be restored is worthless. Regular restore testing is mandatory:
# Automated restore test script
#!/bin/bash
set -e
RESTORE_DIR=/tmp/restore_test
BACKUP_DIR=/backups/weekly
rm -rf $RESTORE_DIR
pgbackrest --stanza=prod --db-path=$RESTORE_DIR restore
pg_ctl start -D $RESTORE_DIR -l $RESTORE_DIR/logfile
sleep 10
psql -d postgres -c "SELECT count(*) FROM pg_database;"
pg_ctl stop -D $RESTORE_DIR
rm -rf $RESTORE_DIR
echo "Restore test PASSED at $(date)"
Cloud Backup Integration
Most cloud providers offer managed backup services:
* **RDS Automated Backups**: Daily snapshot + 5 minutes of WAL. PITR enabled by default.
* **Cloud SQL**: Point-in-time recovery with binary log archiving.
* **Aurora**: Continuous backup to S3 with PITR, no performance impact.
The 3-2-1 rule applies to databases: three copies of data, on two different media, with one off-site. Your backup strategy should verify all three conditions regularly.