Introduction
Regular backups are your safety net against data loss from hardware failures, human error, or security incidents. A backup strategy that isn't tested is no strategy at all.
Key Concepts
- pg_dump: PostgreSQL's built-in tool for creating logical backups — exports data as SQL or a custom binary format.
- Point-in-Time Recovery (PITR): Restoring to any moment in time using base backups plus Write-Ahead Log (WAL) archives.
- Backup Verification: Periodically restoring backups to a test database to ensure they're valid and complete.
Real World Context
A developer accidentally runs DELETE FROM orders without a WHERE clause. Without tested backups, that data is gone forever. With daily backups and WAL archiving, you can restore to one minute before the mistake.
Deep Dive
Manual PostgreSQL Backup
bash# Custom format (compressed, supports parallel restore) pg_dump -h localhost -U postgres -d myapp_production -F c -f backup.dump # SQL format (human-readable) pg_dump -h localhost -U postgres -d myapp_production | gzip > backup.sql.gz
Automated Backup Job
rubyclass DatabaseBackupJob < ApplicationJob queue_as :maintenance def perform timestamp = Time.current.strftime('%Y%m%d_%H%M%S') filename = "backup_#{timestamp}.dump" system("pg_dump -F c -f /tmp/#{filename} $DATABASE_URL") File.open("/tmp/#{filename}") do |file| S3_BUCKET.put_object( key: "backups/#{filename}", body: file, storage_class: 'STANDARD_IA' ) end FileUtils.rm("/tmp/#{filename}") end end
Restore from Backup
bashpg_restore -h localhost -U postgres -d myapp_production -c backup.dump
Backup via Kamal
bash# Execute pg_dump inside the database accessory kamal accessory exec db 'pg_dump -U postgres myapp_production -F c' > backup.dump
Common Pitfalls
- Never testing restores — A backup you've never restored might be corrupt or incomplete. Test restores monthly.
- Storing backups on the same server — If the server fails, you lose both the database and the backups. Always use off-site storage (S3, GCS).
Best Practices
- Automate daily backups — Schedule
DatabaseBackupJobto run daily and upload to S3 with lifecycle policies. - Retain at least 30 days — Keep daily backups for a month, weekly backups for a year, to handle late-discovered issues.
Summary
- Use pg_dump with custom format (-F c) for efficient, restorable backups.
- Automate backups with a background job uploading to S3.
- Test restores regularly — untested backups are unreliable.
- Store backups off-site and retain at least 30 days.
Code Examples
bash
# Create backup
pg_dump -F c -d myapp_production -f backup.dump
# Restore backup (drops and recreates objects)
pg_restore -d myapp_production -c backup.dump
# Backup via Kamal accessory
kamal accessory exec db 'pg_dump -U postgres myapp' > backup.dump