Skip to content

Backup & restore

Docket’s persistent state is two things: the PostgreSQL database and the S3 (or S3-compatible) attachment bucket. Both must be captured for a complete backup.

  • pg_dump and pg_restore (PostgreSQL client tools)
  • aws CLI (for S3 attachment backup/restore)
  • The docket binary (for the rebuild-tickets command)
Terminal window
export DATABASE_URL="postgres://docket:secret@db:5432/docket?sslmode=disable"
export S3_BUCKET="docket-attachments"
export S3_ENDPOINT="http://minio:9000" # omit for AWS S3
./scripts/backup.sh ./backups/2026-04-20

This creates:

  • ./backups/2026-04-20/docket.dump — custom-format Postgres dump.
  • ./backups/2026-04-20/storage/ — copy of all S3 attachments.
Terminal window
export DATABASE_URL="postgres://docket:secret@new-db:5432/docket?sslmode=disable"
export S3_BUCKET="docket-attachments"
export S3_ENDPOINT="http://minio:9000"
export DOCKET_BIN="./docket"
./scripts/restore.sh ./backups/2026-04-20

The restore script:

  1. Runs pg_restore --clean --if-exists to drop and recreate objects.
  2. Syncs attachments back to S3.
  3. Runs docket rebuild-tickets --yes to validate event-sourced integrity by replaying the spine into the projection. The --yes flag confirms the destructive rebuild (it drops FK constraints and truncates the projection tables); the command also takes an exclusive advisory lock and will refuse to run if any docket serve is alive against the target database.

After restore:

  1. Start Docket: ./docket serve
  2. Check health: curl http://localhost:8080/readyz
  3. Spot-check tickets in the UI
  4. Verify attachment downloads work

Run scripts/backup.sh on a cron schedule. Example:

0 2 * * * DATABASE_URL=... S3_BUCKET=... /opt/docket/scripts/backup.sh /backups/$(date +\%Y\%m\%d)

Retain at least 7 daily backups. Test restore quarterly — an untested backup is a hope, not a backup.