Data in the
local_pgdatavolume survivesmake down, but notmake destroy. Take real backups.
This feature is optional and on-demand. Nothing here runs unless you invoke it.
make backup/make restoreare manual; an automated scheduled backup is an opt-in service (make up-backup, off by default) — see doc 12 — Optional Features.
make backup
# -> backups/local_db_YYYYMMDD_HHMMSS.dump.gz (custom-format, gzipped)Under the hood:
docker compose exec -T postgres \
pg_dump -U local_dev -d local_db -Fc | gzip > backups/local_db_<ts>.dump.gzCustom format (-Fc) is recommended: compressed, and pg_restore can do
selective/partial restores from it.
make restore FILE=backups/local_db_20260615_140000.dump.gzUnder the hood:
gunzip -c <file> | docker compose exec -T postgres \
pg_restore -U local_dev -d local_db --clean --if-exists
--clean --if-existsdrops existing objects first, so you restore onto a non-empty DB safely. To restore into a fresh DB,make destroy && make upfirst, then restore.
docker compose exec -T postgres pg_dumpall -U local_dev --globals-only \
> backups/globals.sql # roles/tablespaces
docker compose exec -T postgres pg_dump -U local_dev -d local_db \
> backups/local_db.sql # schema + data as SQLOption A — host cron (simple):
# crontab -e → daily at 02:30
30 2 * * * cd /path/to/postgresql-fdw && make backup >> backups/cron.log 2>&1Option B — in-database with pg_cron (logical dump still needs the host, but you can schedule maintenance):
SELECT cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM (ANALYZE)');
SELECT * FROM cron.job; -- verifyOld dumps pile up. Prune those older than 14 days:
find backups -name '*.dump.gz' -mtime +14 -delete- Backup file exists and is non-zero (
ls -lh backups/) - Target DB reachable (
make health) - Ran restore; checked row counts in a key table
- App reconnected successfully
✅ Next: take it beyond your laptop → 8. Deployment »