Open-source alternatives guide
Litestream vs WAL-G vs pgBackRest 2026
Compare Litestream, WAL-G, and pgBackRest for database backups in 2026. Continuous streaming replication vs WAL archiving vs full-featured backup — which.
TL;DR
Litestream continuously replicates SQLite databases to S3 — it's for SQLite, not Postgres. WAL-G archives Postgres WAL (Write-Ahead Log) to S3/GCS/Azure continuously — sub-second RPO (Recovery Point Objective) with minimal overhead. pgBackRest is a full-featured Postgres backup solution with incremental backups, parallel processing, compression, and encryption. For most self-hosted Postgres deployments: WAL-G for continuous point-in-time recovery, pgBackRest when you need advanced features.
Key Takeaways
- Litestream: Apache 2.0, ~9K stars, Go — SQLite only, real-time S3 streaming
- WAL-G: Apache 2.0, ~4K stars, Go — Postgres WAL archiving to S3/GCS/Azure/SFTP
- pgBackRest: MIT, ~3K stars, C — full backup suite (full/diff/incr), parallel, encryption
- pg_dump: Built into Postgres — logical backups, good for small DBs, not for PITR
- RPO comparison: WAL-G/pgBackRest ~few seconds; pg_dump depends on schedule (hourly = 1hr RPO)
- RTO comparison: WAL-G restore ~5–30 min; pgBackRest ~5 min (parallel); pg_dump restore varies
Understanding Postgres Backup Types
Before comparing tools, understand the backup strategies:
| Type | How It Works | RPO | RTO | Use Case |
|---|---|---|---|---|
| Logical (pg_dump) | SQL dump of data | Hours (cron) | Minutes–hours | Small DBs, schema migrations |
| Physical (base backup) | Copy data directory | Continuous | Minutes | Medium–large DBs |
| WAL archiving | Stream WAL changes | Seconds | Minutes | Production with PITR |
| Streaming replication | Replica follows primary | Near-zero | Failover time | HA, not backup |
WAL archiving + base backup = Point-In-Time Recovery (PITR): restore to any point in time, not just scheduled backup times.
Litestream: Continuous SQLite Replication
Litestream streams every SQLite transaction to S3 in real time. It's specifically for SQLite — not Postgres. But if you're running SQLite (which is increasingly common for small apps, n8n SQLite mode, Forgejo, etc.), Litestream is the best backup tool available.
Why Litestream for SQLite
The classic SQLite problem: you can't just copy an .db file while the process is running (you get corruption). Litestream uses SQLite's WAL mode to capture and stream every page change.
# Install Litestream:
wget https://github.com/benbjohnson/litestream/releases/latest/download/litestream-linux-amd64.tar.gz
tar xzf litestream-linux-amd64.tar.gz
mv litestream /usr/local/bin/
Configuration
# /etc/litestream.yml
access-key-id: your-b2-key-id
secret-access-key: your-b2-application-key
dbs:
- path: /app/data/app.db
replicas:
- url: s3://my-bucket/app-db
endpoint: https://s3.us-west-004.backblazeb2.com
- path: /app/data/sessions.db
replicas:
- url: s3://my-bucket/sessions-db
endpoint: https://s3.us-west-004.backblazeb2.com
- path: /backup/local/sessions.db # Local replica too
# Run as daemon:
litestream replicate -config /etc/litestream.yml
# Or as systemd service:
systemctl enable litestream
systemctl start litestream
Restore from Litestream
# Restore latest:
litestream restore -config /etc/litestream.yml /app/data/app.db
# Restore to specific point in time:
litestream restore -config /etc/litestream.yml \
-timestamp "2026-03-09T12:00:00Z" \
/app/data/app.db
# List available restore points:
litestream generations -config /etc/litestream.yml /app/data/app.db
Docker Integration (run alongside your app)
services:
app:
image: your-app
volumes:
- app_data:/data
litestream:
image: litestream/litestream:latest
command: replicate
volumes:
- app_data:/data
- ./litestream.yml:/etc/litestream.yml
environment:
AWS_ACCESS_KEY_ID: your-key-id
AWS_SECRET_ACCESS_KEY: your-secret-key
volumes:
app_data:
WAL-G: Continuous Postgres WAL Archiving
WAL-G archives Postgres WAL files to cloud storage as they're generated. Combined with periodic base backups, this gives you continuous PITR.
How WAL Archiving Works
Postgres writes → WAL files → WAL-G archives to S3 → Base backup periodically
Restore = apply base backup + replay WAL files up to target time.
Docker Setup with WAL-G
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: myapp
POSTGRES_USER: myapp
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
# WAL-G environment:
WALG_S3_PREFIX: s3://my-bucket/postgres-backups
AWS_ACCESS_KEY_ID: "${AWS_ACCESS_KEY_ID}"
AWS_SECRET_ACCESS_KEY: "${AWS_SECRET_ACCESS_KEY}"
AWS_ENDPOINT: "https://s3.us-west-004.backblazeb2.com" # B2 endpoint
WALG_COMPRESSION_METHOD: brotli # Better compression than zstd default
WALG_DELTA_MAX_STEPS: 6 # Incremental steps before full backup
volumes:
- pg_data:/var/lib/postgresql/data
- ./postgresql.conf:/etc/postgresql/postgresql.conf
volumes:
pg_data:
# postgresql.conf additions:
archive_mode = on
archive_command = 'wal-g wal-push %p'
archive_timeout = 60 # Archive WAL every 60 seconds even if not full
restore_command = 'wal-g wal-fetch %f %p'
Take Base Backups
# Schedule in cron (daily at 1am):
0 1 * * * docker exec postgres wal-g backup-push /var/lib/postgresql/data
# Or from host using docker exec:
docker exec postgres wal-g backup-push /var/lib/postgresql/data
List and Manage Backups
# List backups:
docker exec postgres wal-g backup-list
# LABEL MODIFIED WAL SEGMENT START LSN FINISH LSN HOSTNAME
# base_000000010000000000000001 2026-03-09T03:01:23Z 000000010... 0/1000000 0/1500000 myhost
# Delete old backups (keep last 7):
docker exec postgres wal-g delete retain FULL 7 --confirm
Point-in-Time Recovery
# Step 1: Stop Postgres
docker compose stop postgres
# Step 2: Backup current data dir (safety net)
cp -r /var/lib/docker/volumes/postgres_data/_data/ /tmp/pg-old-data/
# Step 3: Fetch the base backup
docker exec postgres wal-g backup-fetch /var/lib/postgresql/data LATEST
# Step 4: Create recovery.conf (Postgres 11 and earlier)
# OR postgresql.conf additions (Postgres 12+):
cat >> /var/lib/postgresql/data/postgresql.conf << EOF
restore_command = 'wal-g wal-fetch %f %p'
recovery_target_time = '2026-03-09 12:30:00' # Target time
recovery_target_action = 'promote'
EOF
# Also create recovery signal:
touch /var/lib/postgresql/data/recovery.signal
# Step 5: Start Postgres
docker compose start postgres
# Postgres applies WAL until target time, then promotes to read-write
pgBackRest: Full-Featured Backup Suite
pgBackRest is the most feature-rich Postgres backup solution. Used by large-scale Postgres installations. Features: full/differential/incremental backups, parallel processing, compression, encryption, S3 storage, retention policies.
When to Choose pgBackRest over WAL-G
- Need AES-256 encryption at rest (pgBackRest: built-in; WAL-G: relies on S3 SSE)
- Parallel backup/restore — critical for large (100GB+) databases
- Differential and incremental backup types (WAL-G only does delta)
- Detailed reporting and monitoring integration
- Multi-repository support (backup to multiple destinations)
Docker Setup
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: myapp
POSTGRES_USER: myapp
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
volumes:
- pg_data:/var/lib/postgresql/data
- ./pgbackrest.conf:/etc/pgbackrest/pgbackrest.conf
pgbackrest:
image: pgbackrest/pgbackrest:latest
volumes:
- pg_data:/var/lib/postgresql/data:ro
- ./pgbackrest.conf:/etc/pgbackrest/pgbackrest.conf
- pgbackrest_spool:/var/spool/pgbackrest
command: ["info"] # Replace with actual backup command in cron
volumes:
pg_data:
pgbackrest_spool:
Configuration
# pgbackrest.conf
[global]
repo1-path=/var/lib/pgbackrest
repo1-s3-bucket=my-backup-bucket
repo1-s3-endpoint=s3.us-east-1.amazonaws.com
repo1-s3-key=your-access-key
repo1-s3-key-secret=your-secret-key
repo1-s3-region=us-east-1
repo1-type=s3
repo1-cipher-type=aes-256-cbc # Encrypt all backups
repo1-cipher-pass=strong-encryption-key
# Retention:
repo1-retention-full=2 # Keep last 2 full backups
repo1-retention-diff=6 # Keep last 6 differential
repo1-retention-archive=30 # WAL for last 30 days
[myapp]
pg1-path=/var/lib/postgresql/data
Commands
# Initialize repository:
pgbackrest --stanza=myapp stanza-create
# Full backup:
pgbackrest --stanza=myapp --type=full backup
# Incremental backup (after full):
pgbackrest --stanza=myapp --type=incr backup
# List backups:
pgbackrest --stanza=myapp info
# Restore latest:
pgbackrest --stanza=myapp --delta restore
# Restore to point in time:
pgbackrest --stanza=myapp restore \
--target="2026-03-09 12:00:00" \
--target-action=promote
Simple pg_dump: When Is It Enough?
For small databases (< 10GB) and moderate RPO requirements (hourly is acceptable), pg_dump is completely sufficient:
#!/bin/bash
# backup-postgres.sh
DB_NAME=myapp
BACKUP_DIR=/backup/postgres
mkdir -p "$BACKUP_DIR"
# Full logical dump:
docker exec postgres pg_dump -U myapp "$DB_NAME" | \
gzip > "${BACKUP_DIR}/${DB_NAME}-$(date +%Y%m%d-%H%M%S).sql.gz"
# Keep last 14 backups:
ls -t "${BACKUP_DIR}/${DB_NAME}-"*.sql.gz | tail -n +15 | xargs -r rm
# Upload to B2:
rclone copy "${BACKUP_DIR}" b2:my-bucket/postgres-dumps
# Hourly backups:
0 * * * * /usr/local/bin/backup-postgres.sh
pg_dump limitations: No PITR (you can only restore to a backup timestamp), not suitable for > 50GB databases (too slow), doesn't capture in-flight transactions during dump.
Operational Setup: Storage Backends and Cost
Choosing the right object storage backend for your backup pipeline significantly affects both cost and restore speed. All three tools support S3-compatible storage, giving you flexibility beyond AWS.
Backblaze B2 is the most cost-effective choice for most self-hosters. At $0.006/GB/month for storage and free egress to CDN providers, it's roughly a quarter of AWS S3's price. WAL-G and Litestream both work with B2 by setting the endpoint to Backblaze's S3-compatible URL. pgBackRest requires additional configuration for B2 compatibility but supports it through the S3 backend with a custom endpoint. For teams running multiple self-hosted services that all need backup storage, B2's cost advantage compounds across services.
AWS S3 remains the reference implementation. If you're already in the AWS ecosystem, S3's integration with IAM roles simplifies credential management — the Postgres host can be given an IAM instance profile that grants S3 write access without storing long-lived credentials in the environment. S3 Glacier Instant Retrieval is worth considering for older backups that are kept for compliance but rarely restored.
Hetzner Storage Box and Hetzner Object Storage are compelling options for European self-hosters who want backup storage co-located with their compute. Hetzner's pricing is competitive and the network latency between Hetzner Cloud instances and Hetzner storage is effectively zero, which speeds up large backup transfers.
Storage sizing: Plan for 2-3x your database size in backup storage per retention period. A 10 GB database with 30-day WAL retention and weekly full backups consumes roughly 25-40 GB of storage depending on write volume. WAL-G's compression (brotli is more effective than the default zstd for many workloads) and incremental delta backups reduce this significantly for write-heavy databases.
Backup verification: All three tools support a verify or check operation that validates backup integrity without a full restore. Run this weekly. A backup that was never verified may silently fail to restore due to storage corruption, version incompatibility, or configuration drift. For teams running WAL-G, schedule a monthly test restore to a separate Postgres instance in a staging environment — this is the only way to confirm the full recovery path works end to end. For insight into the broader self-hosted database backup landscape, the best self-hosted database tools comparison covers this ground in detail.
Security and Compliance Considerations
Database backups are copies of your most sensitive data, which makes their security posture as important as the database's own security.
Encryption at rest: pgBackRest is the only tool in this comparison with native client-side encryption. When you set repo1-cipher-type=aes-256-cbc and repo1-cipher-pass, backups are encrypted before leaving the Postgres host. This matters in two scenarios: when the backup storage provider is not fully trusted, and when regulatory requirements mandate encryption of data at rest regardless of storage location. WAL-G and Litestream rely on the storage provider's server-side encryption (S3 SSE), which is transparent to the data but doesn't protect against a compromised storage provider account.
Credential isolation: Backup credentials — the API keys or IAM roles that allow writing to your backup storage — should be scoped to write-only access on the backup bucket and nothing else. A compromised Postgres host should not give an attacker the ability to delete your backups. Configure separate credentials for backup upload (write-only) and backup restore (read-only) so that the credentials stored on the database server cannot be used to destroy the backup history.
Retention and compliance: For applications with regulatory requirements (GDPR, HIPAA, SOC 2), understand the implications of your retention window. GDPR's right to erasure applies to backups — if a user requests deletion, you may need to either restore and purge backups or document why point-in-time backups make surgical deletion impractical. Maintain a documented backup policy that specifies retention windows, storage destinations, and access controls. WAL-G's delete retain command and pgBackRest's retention configuration make policy enforcement automatable.
Network security: Backup traffic should use encrypted transport. S3-compatible storage uses HTTPS by default. If you're backing up to an SSH/SFTP destination (WAL-G supports this), ensure the host key is verified and use a dedicated SSH key pair for backup access rather than reusing your primary server management key.
Monitoring backup jobs: Silent backup failures are one of the most common data loss scenarios. A cron job that fails silently for three weeks leaves you with three-week-old backups you don't know are stale. For WAL-G cron jobs, pipe output to a health check endpoint (Healthchecks.io or your self-hosted equivalent) that alerts if the job doesn't check in on schedule. pgBackRest has built-in monitoring output compatible with Nagios/Icinga checks.
Disaster Recovery Planning and Testing
The practical value of any backup strategy depends entirely on how quickly and reliably you can actually restore from it. Most teams configure backups without systematically testing recovery — this is the gap that turns backup infrastructure into false confidence.
Define your recovery objectives first: Before choosing between WAL-G and pgBackRest, establish your RTO (Recovery Time Objective) and RPO targets. An RTO of four hours and RPO of one hour is achievable with pg_dump and hourly cron jobs. An RTO of 30 minutes and RPO of five minutes requires WAL archiving with Litestream or WAL-G. An RTO of 15 minutes for a 500 GB database requires pgBackRest's parallel restore functionality. Matching the tool to the objective prevents over-engineering small databases with complex tooling and under-provisioning critical ones.
Test recovery quarterly: Schedule a quarterly disaster recovery drill. Spin up a separate database host, restore from backup to a point in time 48 hours in the past, and verify that applications connect and data integrity checks pass. Document the procedure and actual measured recovery time. This data is valuable for capacity planning and gives you confidence in recovery claims when they matter.
Document the runbook: Write down every step required to recover from each failure scenario: single table corruption, disk failure with data loss, accidental mass deletion, and full host failure. Include the exact commands, environment variables required, and expected output at each step. Store this runbook somewhere accessible without the database — not in the database you're recovering. For teams managing multiple self-hosted services, the Grafana and Prometheus observability stack guide covers how to monitor backup job health and storage consumption alongside application metrics.
Offsite and offline copies: Cloud storage is not inherently safe from accidental deletion, ransomware, or vendor account compromise. For critical data, maintain at least one backup copy in a separate cloud account or provider. WAL-G and pgBackRest both support multiple repositories. Litestream supports multiple replica destinations in its configuration. The additional storage cost of a second destination is negligible compared to the cost of data loss.
Tool Selection Guide
Use Litestream if:
→ Your application uses SQLite (n8n SQLite, small apps, embedded DBs)
→ You want continuous sub-second RPO for SQLite
→ Dead simple setup — just a sidecar process
Use WAL-G if:
→ Postgres database < 200GB
→ You want PITR (restore to any point in time)
→ S3/B2/GCS storage backend
→ Simple configuration preferred
→ Good enough for most production self-hosted workloads
Use pgBackRest if:
→ Postgres database > 200GB (parallel processing helps)
→ Encryption at rest is required
→ Need differential/incremental backup granularity
→ Managing multiple Postgres instances
→ Enterprise or regulated environment
Use pg_dump if:
→ Database < 10GB
→ Hourly RPO is acceptable
→ Simplest possible solution
→ Schema-only backups for version control
→ Migration between Postgres versions
Integrating Backups into Your Self-Hosted Stack
Database backup doesn't happen in isolation. Most self-hosted deployments run multiple services — a wiki, a monitoring stack, a CRM, a newsletter tool — all of which need backups. A coherent multi-service backup strategy is significantly less operational overhead than per-service ad hoc approaches.
The most common pattern for small to medium self-hosted stacks is a unified backup agent that runs on a schedule, captures state from each service, and ships everything to a single object storage destination with deduplication. Restic is the most widely used tool for this — it handles deduplication, encryption, and multi-destination shipping. For Postgres databases specifically, the workflow is: pg_dump to stdout, pipe into a restic backup command, restic deduplicates and encrypts, ships to Backblaze B2 or another S3-compatible store.
For SQLite databases running alongside Postgres in the same infrastructure (n8n in SQLite mode, small embedded apps), Litestream handles continuous replication to a separate prefix in the same B2 bucket. This gives you a unified storage destination — one bucket, multiple service backups, one set of access credentials to manage.
Monitor backup job health centrally. Healthchecks.io (which has a self-hosted version) lets each backup job ping a check URL on success. If the ping doesn't arrive within the expected window, you receive an alert. This transforms silent backup failures from an unknown risk into an observable operational event. For teams already running a Grafana and Prometheus observability stack, backup success metrics can feed into the same dashboard as application uptime and error rates — giving you a single operational view of infrastructure health.
The ROI calculation on robust backup infrastructure is straightforward. A single data loss incident — even one that costs four hours of team time to recover from — costs more than a year of backup tooling and VPS storage. For teams tracking the financial case for self-hosting vs SaaS, backup infrastructure is one of the costs that doesn't appear in the simple "VPS vs subscription" calculation but must be included in an honest total cost of ownership analysis. Database backup also intersects with the broader self-hosting security checklist — backup encryption, access credential rotation, and off-site storage separation are security requirements, not just operational ones. Teams using self-hosted PostgreSQL as the backend for tools like Supabase, Appwrite, or PocketBase benefit from applying these backup strategies to all database-backed services in their stack, not just their primary application database.
See all open source database backup tools at OSSAlt.com/categories/backup.
The SaaS-to-Self-Hosted Migration Guide (Free PDF)
Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.
Join 300+ self-hosters. Unsubscribe in one click.