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.