A sound pg_dump method that includes retention policies, S3 compatible storage, and restore tests for self-managed Postgres.
The two failure modes you are insuring against
There are two types of disasters that database backups help guard against. The first type is related to infrastructure failures such as disk failures, server deletion, and problems with the provider’s account. The second and far more likely type of disaster is data corruption due to data errors such as a flawed migration, a bug in the bulk update script, or a DELETE without a WHERE clause. The first problem requires an off-site backup, while the second one requires history since the damage is discovered after several days.
The baseline: scheduled logical dumps
If your database is around 50 GB, pg_dump is easy to use, highly portable, and has been tested for years. Dump in a custom format to enable compression and select restore:
-Fc (custom format) compresses and lets you restore single tables later
Dump from a scheduled job on the server, not your laptop
Above ~50 GB, or with strict recovery-point requirements, graduate to WAL archiving (pgBackRest or wal-g) for point-in-time recovery
inside or against the container
pg_dump -U app -Fc appdb > backup-$(date +%F).dump
# verify the archive is readable (cheap, catches corruption)
pg_restore --list backup-2026-05-09.dump > /dev/null && echo OK
Ship dumps off the server
Having a backup stored in the same drive as the database will defend absolutely nothing important. Ship all your dumps to a compatible object store that resides in a separate failure zone: AWS S3, Cloudflare R2, Backblaze B2, or Hetzner Object Storage. When it comes to object stores for backing up volumes, R2 and B2 reign supreme by offering the most competitive pricing of about half a cent per GB-month with zero-cost or negligible-cost data egress upon restoration.
Use write-only permissions for uploading credentials on the object storage whenever possible and enable bucket versioning as a secondary measure.
Retention that follows how mistakes are detected
The standard grandfather-father-son rotation process is there because mistakes in the data are detected later in time. Maintain 7 daily, 4 weekly and 6 monthly dumps; this ensures that “restore yesterday” and “what was this table in February?” are satisfied and storage is limited to 17 dumps per database.
Peon’s managed databases do this via configuration settings; configure the schedule, retention numbers and S3 location through the dashboard, and Peon handles the dumping, uploading, pruning and integrity checking. Restores can be done in one click, either into the production database or the scratch database.
Schedule restoration testing on a schedule
Untested backups are hopes, not plans, and a failure in the backup system is silent: expired credentials, full disks, or a schema update that stops the dump process. Test the restoration of the latest dump to a test database, and count the rows against the production system, and time it. That time is your true recovery time; better to learn it during a drill than a disaster.
createdb restore_test
pg_restore -d restore_test --no-owner backup-2026-05-09.dump
psql restore_test -c "SELECT count(*) FROM users;"
The checklist
Nightly pg_dump -Fc, automated on the server
Uploaded to S3-compatible storage in a different provider or region
7/4/6 retention pruning, automated
Bucket versioning on; upload credentials cannot delete
Quarterly restore drill with a timed, written procedure
Alert if a backup fails or is smaller than expected; silence must be suspicious
Deploy it on your own server Peon
Top comments (0)