Django Backup and Recovery Checklist

Check that Django backups actually protect you: what to back up, schedules, off-site copies, encryption, retention, restore drills, and monitoring.

Problem statement

Backups fail quietly. A cron job stops running after a server rebuild, a dump completes but contains an empty database because credentials changed, an S3 bucket lifecycle rule deletes the only copies after 30 days, or the encryption passphrase lives only in the memory of someone who left. None of this is visible until a restore is needed, which is the worst moment to discover it.

This checklist reviews a Django project's backup and recovery setup end to end: what is backed up, how often, where copies live, who can reach them, how restores are tested, and how failures are detected. It covers self-managed PostgreSQL and managed databases, media files, and the configuration needed to rebuild an environment.

What recovery needsDatabasedumps or WALMedia filesobject storageSecretsvault or storeRunbooktested restoreData alone is not recovery; you also need the configuration to run it.

Quick answer

  1. Inventory everything needed to rebuild: database, media, configuration and secrets, infrastructure definitions, and DNS records.
  2. Match backup frequency to your acceptable data loss (RPO): nightly dumps for a 24-hour RPO, continuous archiving or managed point-in-time recovery for minutes.
  3. Store copies off the server and outside the production account, encrypted, with retention that covers late-discovered problems.
  4. Restrict who and what can delete backups; application credentials must not be able to.
  5. Monitor every backup job with heartbeats and verify backup contents, not just job exit codes.
  6. Test restores on a schedule and measure how long a full restore takes.
  7. Document the restore procedure so someone else can follow it.

Checklist

1. Inventory: what must be recoverable

ItemTypical approachNotes
Databasepg_dump and/or continuous archiving, or managed backupsthe core data
Media and uploadsobject storage versioning plus copies, or restic snapshotsoften the largest volume
Secrets and configurationsecret manager with its own backup, or encrypted exportneeded to start the app
Infrastructure definitionsGit repository (Terraform, Ansible, Compose files)needed to rebuild servers
Application code and imagesGit remote and container registryverify they are not only on one machine
DNS recordsexported zone file or infrastructure codeneeded for cutover
recoverable means all of theseBackup methodOften forgotten?Databasepg_dump or PITR✓rarelyMedia uploadsobject storage versioning or sync!oftenSecrets and envsecret manager or encrypted copy✕very oftenServer configGit or infrastructure as code!oftenA database without its SECRET_KEY and media is only a partial recoverydjango-deployment.com
Losing SECRET_KEY invalidates sessions and signed data, not the database itself.

Anything not on this list must be reproducible from what is, or it is a gap.

2. Database backup method matches the RPO

  • Nightly logical dumps: simple and portable; RPO up to 24 hours.
how much could you lose?Nightly pg_dumpup to 24 hpg_dump every 6 hoursup to 6 hWAL archiving / PITRminutes0 h6 h12 h18 h24 hhoursPick the method from the RPO, not the other way rounddjango-deployment.com
Managed databases usually include PITR; check the retention window.
pg_dump --format=custom --compress=6 --file="/var/backups/myapp-$(date +%F).dump" "$DATABASE_URL"
  • Continuous archiving (PITR): base backups plus WAL, with tools such as pgBackRest or WAL-G; RPO of minutes, restore to any point in time.
  • Managed service backups: automated daily snapshots plus transaction log retention; check the retention window and that PITR is enabled.

Verify the method in use answers your RPO, and that the dump uses a role able to read all required data.

3. Schedule and automation

What to check:

systemctl list-timers | grep -i backup
sudo crontab -l | grep -i backup

Guidelines:

  • Backups run automatically, not manually.
  • Media backups run after database backups, so files referenced by the database exist.
  • Jobs use set -euo pipefail (or equivalent) so a failing step does not produce a truncated backup that looks successful.
  • Long-running backups do not overlap; use systemd timers (which skip while active) or flock.

4. Off-site and off-account copies

Guidelines:

  • Copies exist outside the application server.
  • At least one copy is in a different cloud account, provider, or region.
  • Backup storage credentials are separate from application credentials.
  • Application and server credentials cannot delete backups (append-only or write-only access, object lock, or versioning without delete permission).
  • Restore credentials are documented and accessible during an incident, including if the production account is unavailable.
a backup attackers cannot deleteSame account and server✕one stolen credential deletes both✕ransomware encrypts backups too✕region outage takes bothSeparate account, locked✓write-only credentials from prod✓object lock or versioning✓another regionProduction should be able to add backups, never remove themdjango-deployment.com
Test that the production credentials really cannot delete from the backup bucket.

5. Encryption

Guidelines:

  • Backups encrypted at rest (restic encrypts by default; pg_dump output needs encryption applied, for example with age or provider-side encryption).
  • Encryption keys or passphrases stored in a password manager separate from the backups themselves, with at least two people able to retrieve them.
  • Transfers over TLS.

6. Retention

Guidelines:

  • Retention covers problems discovered late (a corrupted record noticed weeks later), for example 14 daily, 8 weekly, and 12 monthly copies.
  • Retention policy applied automatically (restic forget --prune, lifecycle rules, or provider settings), not by manual deletion.
  • Legal or contractual retention requirements met, and personal data deletion obligations considered: backups containing deleted user data need a documented policy.

7. Monitoring and verification

Job success is not enough; verify the artifact:

# Verify a PostgreSQL custom-format dump is readable and non-trivial
pg_restore --list /var/backups/myapp-$(date +%F).dump | head -5
ls -lh /var/backups/myapp-$(date +%F).dump

Guidelines:

  • Heartbeat monitoring for every backup job, alerting when a run is missing.
  • Alert on unusually small backups (for example less than 80 percent of the previous size), which can indicate partial dumps.
  • restic check or equivalent integrity checks on a schedule.
  • Backup metrics visible on a dashboard: last successful run, size trend, restore test date.

8. Restore procedures documented

For each backup type, a written procedure with commands:

# Restore a dump into a scratch database
createdb myapp_restore_test
pg_restore --dbname=myapp_restore_test --no-owner --jobs=4 /var/backups/myapp-2026-09-16.dump
psql -d myapp_restore_test -c "SELECT count(*) FROM auth_user;"

Include: where backups live, how to get credentials, expected duration, verification queries, and how to point the application at restored data.

9. Restore testing schedule

TestFrequencyWhat it proves
Automated restore of the latest dump into a scratch database with row count checksweekly or nightlybackups are readable and non-empty
Restore database and media into staging; run the app against themquarterlythe full dataset works with the application
Full environment rebuild from infrastructure code plus backupsyearlythe recovery path works without the original servers
a restore test, start to finish1Fresh environmentnever the production database2Restore database and mediafrom the off-site copy3Run the app against itsame release, restored secrets4Check row counts and a loginrecent data present5Record time takenthat is your real RTOA backup that has never been restored is a hope, not a backupdjango-deployment.com
Automate the restore test so it runs even when nobody remembers.

Record the date and duration of each test. A backup system without a recent successful restore is an assumption.

10. Point-in-time recovery drill

If you rely on PITR, practice restoring to a specific timestamp, because the procedure differs from restoring a plain dump:

  1. Choose a target time (for example five minutes before a simulated bad migration).
  2. Restore a base backup and replay WAL to that time, or use the managed service's PITR feature.
  3. Verify data reflects the target time.
  4. Record the total time taken.

11. Special data considerations

  • Sessions and caches: usually not worth backing up; they regenerate.
  • Search indexes: rebuildable from the database; document the rebuild time.
  • Generated files (thumbnails, exports): decide whether to back up or regenerate.
  • Personal data: restores may reintroduce data a user asked to delete; have a process for re-applying deletions after a restore.

Verify

Verification check:

  • every item in the inventory has a backup method and a documented restore path
  • backups are stored off-server, in another account or region, and encrypted
  • application credentials cannot delete backups
  • a restore test succeeded recently, with the date recorded
  • monitoring alerts when a backup job does not run or produces an unusually small artifact
  • at least two people can access backup storage and encryption keys

Explanation

A backup system is a chain: data selection, scheduling, transfer, storage, retention, access control, and restore. A break anywhere makes the whole chain useless, and most breaks are silent. Regular restore tests exercise the entire chain and are the only reliable evidence that recovery works, which is why they belong on a schedule rather than in the plan for the next incident.

Edge cases / notes

Managed database backups

Providers handle scheduling and storage, but retention windows are limited and backups usually live in the same account. Export periodic copies elsewhere if account-level loss is in your threat model.

Very large databases

Restore time grows with size and can exceed your RTO even when backups are perfect. Measure it, and consider replicas or faster restore methods if the measured time is too long.

Encryption key loss

An encrypted backup without its key is not a backup. Store keys with the same care as the backups, in a separate location, with documented recovery access.

Common mistakes

  • Backing up the database but not media or configuration.
  • Keeping the only copies on the production server or in the production account.
  • Monitoring job exit codes but never checking backup contents.
  • Never restoring, or restoring only in the same environment that created the backup.

Next steps

FAQ

What should a Django backup include besides the database?

User uploads, configuration and secrets, infrastructure definitions, DNS records, and anything else required to rebuild the environment from nothing.

How often should Django database backups run?

Frequently enough to meet your acceptable data loss. Nightly dumps allow up to a day of loss; continuous archiving or managed point-in-time recovery reduces that to minutes.

How do I know my backups are usable?

Restore them. Automate a weekly restore into a scratch database with validation queries, and run fuller restore drills into staging quarterly.

Should application servers be able to delete backups?

No. Use separate credentials with append-only or write-only access, and enable versioning or object lock so a compromised application cannot destroy recovery data.

Keep going