Automate Database and Media Backups With django-dbbackup
Use django-dbbackup to back up the Django database and media to S3 or other storage on a schedule: configuration, compression and GPG encryption, cleanup, restores with dbrestore and mediarestore, and its limits compared with native tools.
Problem statement
Many Django projects launch without automated backups, or with a shell script someone wrote once and nobody monitors. django-dbbackup adds management commands that dump the database and archive media files to any Django storage backend (local disk, S3, R2, SFTP), with optional compression, encryption, and cleanup of old backups. Run on a schedule with monitoring, it gives a small team reliable, off-site backups that restore with a single command, as long as you understand where it fits next to native tools and managed backups.
pip install django-dbbackupand adddbbackuptoINSTALLED_APPS.- Configure
STORAGES["dbbackup"](Django 4.2+) orDBBACKUP_STORAGEto point at a private S3 bucket or other off-site storage. - Schedule
python manage.py dbbackup --clean --compress(andmediabackupif media is on disk) daily with a timer, Beat, or a CronJob. - Encrypt with
--encryptand a GPG recipient, or rely on bucket encryption plus strict access. - Keep retention with
--cleanandDBBACKUP_CLEANUP_KEEP, plus bucket lifecycle rules. - Test restores regularly with
dbrestoreinto a scratch database, and add heartbeat monitoring.
Step-by-step solution
1. Install and configure storage
INSTALLED_APPS += ["dbbackup"]
STORAGES = {
"default": {"BACKEND": "storages.backends.s3.S3Storage", "OPTIONS": {"bucket_name": "myapp-media"}},
"staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
"dbbackup": {
"BACKEND": "storages.backends.s3.S3Storage",
"OPTIONS": {"bucket_name": "myapp-backups", "location": "db", "default_acl": "private"},
},
}
DBBACKUP_CLEANUP_KEEP = 14
DBBACKUP_CLEANUP_KEEP_MEDIA = 7
Use a separate bucket from media, in another region or account if possible, with credentials that can write backups but ideally not delete them (deletion handled by lifecycle rules).
2. Take backups
python manage.py dbbackup --compress --clean
python manage.py mediabackup --compress --clean # only if media lives on local disk
python manage.py listbackups
For PostgreSQL, dbbackup runs pg_dump with your Django connection settings, so the PostgreSQL client tools must be installed in the image or server, at a version at least as new as the server.
3. Encrypt
python manage.py dbbackup --compress --encrypt
with DBBACKUP_GPG_RECIPIENT = "backups@example.com" and the public key imported on the server (python-gnupg installed). Keep the private key offline or in a secrets manager; without it, encrypted backups cannot be restored. Bucket-side encryption (SSE-S3 or KMS) protects at rest but not against someone with bucket read access.
4. Schedule and monitor
# /etc/systemd/system/dbbackup.service
[Service]
Type=oneshot
User=deploy
WorkingDirectory=/srv/app/current
EnvironmentFile=/etc/myapp/env
ExecStart=/srv/app/current/.venv/bin/python manage.py dbbackup --compress --encrypt --clean
ExecStartPost=/usr/bin/curl -fsS -m 5 https://hc-ping.com/<uuid>
# dbbackup.timer
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
A heartbeat check alerts if a night's backup does not run.
5. Restore
python manage.py dbrestore --decrypt --uncompress --database default # latest backup
python manage.py dbrestore -i default-2026-10-02-023000.psql.gz.gpg --decrypt --uncompress
python manage.py mediarestore --uncompress
Practise on a scratch database first (point settings at it with an environment variable), then compare row counts and log in. Restoring over production overwrites data; take a fresh backup before doing it.
Verification check: listbackups shows a new backup each day in the bucket, old ones are pruned, a monthly restore into a scratch database succeeds with matching row counts, and the heartbeat dashboard is green.
Explanation
django-dbbackup is a thin, Django-aware wrapper: it reads database settings to call the right dump tool (pg_dump, mysqldump, or SQLite file copy), streams the result through optional compression and GPG encryption, and writes it to a Django storage backend, which makes off-site storage a settings change. Media backups archive MEDIA_ROOT. Its value is convenience and consistency for small teams; it does not provide continuous point-in-time recovery, so data written between backups can be lost.
Edge cases / notes
- Large databases make single dumps slow; consider native tools with parallel jobs or managed snapshots.
- Media on S3 does not need
mediabackup; use bucket versioning and replication instead. - Docker images need
postgresql-clientinstalled forpg_dump. - Consistency between database and media backups is not atomic; back up the database first, then media.
Next steps
- Understand the native tools with Backup and Restore PostgreSQL for Django.
- Review the whole plan with the Django Backup and Recovery Checklist.
FAQ
What does django-dbbackup do?
It provides management commands to back up and restore the database and media files to Django storage backends.
Does django-dbbackup replace managed database backups?
No. Use it as an additional off-site copy; managed services add point-in-time recovery.
Why does dbbackup fail with pg_dump errors?
The PostgreSQL client tools are missing or older than the server. Install a matching pg_dump.
How do I restore a django-dbbackup backup?
Run python manage.py dbrestore (with --decrypt and --uncompress if used), ideally into a scratch database first.