Backups and restore
Nightly off-database backups to your own R2, and a disaster-recovery restore path
Cusp gives you three layers of recovery, and it helps to know which one you reach for. Version history undoes a change to a single entity. Site-wide time travel reconstructs the whole site as it was at a past moment, in place. Backups are the layer below both: a complete, off-database snapshot written to your own R2, for the day the database itself is lost or corrupted. This guide is about that bottom layer.
The nightly backup
The ExportBackup workflow runs once a day at 03:00 UTC. It is self-scheduling — there is no cron trigger; the workflow sleeps until its next run with step.sleepUntil — so it survives redeploys without a separate scheduler. Each run dumps every D1 table, takes an inventory of your media objects, writes a manifest, and wraps the whole thing into a single gzipped tarball at backups/{timestamp}/backup.tar.gz in your R2 bucket, recording the archive's SHA-256 and the row and object counts it captured.
Because the archive lives in the same R2 bucket as your media and rendered pages, it stays inside the one-Worker, one-bucket model — there is no external backup service and no second account to configure. There is no automated retention in v1: old archives accumulate in R2, and the daily pruning workflow only trims entity version history, never backups. The admin Health page lists your recent backups with their sizes so you can decide when to prune archives yourself.
Watching backups on the Health page
The Health page (administrator-only) is where you confirm the safety net is working. It lists recent backups with their status — done for a successful run, or the failure reason if one broke — alongside recent restore imports, time-travel restores, and the persisted ExportBackup and PrunePolicies instance IDs. Run backup now triggers an ExportBackup run on demand, so you can take a fresh snapshot before a risky change rather than waiting for 03:00. The page auto-refreshes while a backup, import, or restore is in flight, but it reports workflow liveness only — it does not offer a restart button.
Restoring from a backup
Restore from backup lives under the Restore from backup item in the sidebar. You pick a completed backup and the ImportContent workflow rebuilds the deployment from it. Restore is deliberately a disaster-recovery operation, not an everyday undo: it refuses to run against a database that already holds content. It verifies the target is empty, then inserts the backup's rows — it never overwrites or merges into live data.
Which recovery tool to use
- A wrong edit to one document, setting, theme, or content type — open its version history and restore the earlier version. The restore is itself recorded as a new version.
- A change that touched many entities, or "what did the whole site look like last Tuesday?" — use site-wide time travel to browse and restore the entire site at a timestamp.
- The database is gone or corrupted, or you are standing up a replacement deployment — restore from a backup into an empty database.