Backups and recovery
The worker backs up the database and media originals every night, keeps a sensible history, and tests the latest backup every week by restoring it into a scratch database. You don’t have to remember to do anything, but you should know where backups go and keep the encryption key safe.
Fix small mistakes without a backup
Section titled “Fix small mistakes without a backup”Most mistakes don’t need a restore. The admin keeps history for you:
| Problem | Fix |
|---|---|
| A bad edit was published | Open the item, go to its history, pick the good revision, Restore, then publish again. See Revisions. |
| Something was deleted | Deleted content goes to the Trash first, where it can be restored. |
| A page’s address changed and old links break | A redirect is created automatically. Check Content → Redirects. |
| The design looks wrong after a change | Design tokens and templates have their own history with restore. |
| A theme switch went badly | Switch back. Each theme keeps its own customizations. |
| A plugin breaks pages | Deactivate it under Extensions. Its data is kept. |
What is backed up
Section titled “What is backed up”- The whole database, with
pg_dump: content and every revision, people, settings, design, plugin data. - Media originals (the files people uploaded). Resized image versions aren’t backed up; the worker recreates them.
Backups go to the media storage by default. It’s much safer to send them somewhere else: a bucket at another provider or account (BACKUP_STORAGE_DRIVER=s3), or a separately mounted disk (local).
Set BACKUP_ENCRYPTION_KEY to encrypt backups. A backup can’t be restored without the key, so keep a copy away from the server.
Schedule and retention
Section titled “Schedule and retention”| Setting | Default | Meaning |
|---|---|---|
BACKUP_CRON |
30 2 * * * |
Back up every night at 02:30. |
BACKUP_KEEP |
14 | Keep the newest 14 backups… |
BACKUP_KEEP_WEEKLY |
8 | …plus one per week for 8 weeks… |
BACKUP_KEEP_MONTHLY |
12 | …plus one per month for a year. |
BACKUP_VERIFY_CRON |
15 4 * * 0 |
Restore drill every Sunday at 04:15. |
A failed backup or drill shows on the admin dashboard.
Commands
Section titled “Commands”Run these on the server, with the same environment as the site (in Docker: docker compose -f docker/compose.yml run --rm migrate node packages/backup/src/cli/main.ts …).
pnpm backup # back up nowpnpm backup list # list backupspnpm backup verify latest # restore drill into a scratch database; the live site is untouchedpnpm backup restore latest --yes # replace the database with a backup (stop web and worker first)Restoring
Section titled “Restoring”- Stop
webandworker. If the database still works, take a fresh backup first: everything after the backup you restore will be lost. - Pick a backup with
pnpm backup list. - Run
pnpm backup restore <id> --yes. It checks the backup’s checksum, replaces the database in one step, and puts back any missing media files. - Run
pnpm db:migrate, then startworkerandweb, sign in, and check a few pages.
The full step-by-step procedures, including rebuilding a lost server, rotating the encryption key, and moving hosts with a site export, are in the recovery guide.
Moving to another host
Section titled “Moving to another host”Settings → Download JSON export saves all content, revision history, menus, patterns, design, plugin data, and media addresses in one file. On the new install, run setup, then use Settings → Import a site. The worker copies the media files across from the old site, so keep it running until the import finishes. People, sessions, and API tokens are not included: invite people again, and re-create webhooks.