Skip to main content

Backups and restore

Volume snapshots via `tale backup`, the automatic pre-migration snapshot, retention, the off-host copy, and the `tale restore` drill.

4 min read

Tale's backup unit is the volume snapshot: a paused, checksummed tar of every data volume in the instance, written into a dedicated backups volume that lives next to the data it protects. The CLI takes one automatically before any deploy step that can migrate data, and tale backup takes one on demand. Recovery is tale restore <snapshot-id> plus a redeploy of the matching version — that pair is the answer to a failed upgrade, and the reason tale rollback can afford to refuse anything beyond a patch step.

The architecture context lives in Container architecture; this page covers what a snapshot contains, when one is taken, how the copy gets off the host, and the restore walk.

What a snapshot contains

VolumeHolds
db-dataPostgres — agents, runs, the audit log
convex-dataOrg config, provider secrets, uploaded branding
rag-dataThe vector index built from your documents
crawler-dataCrawled website knowledge
caddy-data, caddy-configTLS certificates and proxy state

Each snapshot is a directory named like 20260611-142530-deploy inside the project's backups volume: one .tar.gz per volume, a .sha256 sidecar each, and a manifest.json written last. A directory without a manifest is an incomplete snapshot — it never shows up in listings and can never be restored. Two things live outside the volumes and need separate capture: the project workspace (the directory holding tale.json) and .env.

When snapshots are taken

tale deploy snapshots before its first mutating step whenever the deploy can change data: the target version differs from the running one, or a host-config push (--override / --override-all) is requested. While each volume is tarred, the containers using it are paused for a few seconds so the archive is crash-consistent — a live copy of a running Postgres directory is not restorable.

A failed snapshot aborts the deploy. --skip-backup overrides that on tale deploy, which leaves your own external backups as the only recovery path — the flag logs a loud warning for exactly that reason.

bash
# Take a snapshot right now
tale backup

Retention

Rotation keeps the newest five snapshots and everything from the last 14 days — whichever is more generous. A snapshot is deleted only when it is both beyond the count window and older than the age window, so a quiet instance keeps its last snapshots indefinitely. Override the windows with BACKUP_KEEP_COUNT and BACKUP_KEEP_DAYS in .env.

Off-host copy

The snapshots live on the same host as the data they protect — a dead disk takes both. Point your existing backup tooling (Restic, Borg, Velero, cloud-provider snapshots) at the backups volume, and capture the project workspace and .env in the same job. Tale does not ship an upload step — keeping the off-host copy under your existing backup contract is deliberate.

bash
# crontab on the host — hourly Restic copy of the backups volume to S3
0 * * * * restic -r s3:s3.amazonaws.com/bucket/tale backup \
  /var/lib/docker/volumes/<project-id>_backups/_data

Find the volume's host path with docker volume inspect <project-id>_backups; the project id lives in tale.json.

Restoring a snapshot

tale restore without arguments lists what is available; with an id it verifies the checksums, wipes the data volumes, and extracts the snapshot. It refuses while any project container runs — pass --stop to stop them — and asks for confirmation before touching anything.

bash
# See what's available
tale restore

# Stop the stack and restore
tale restore 20260611-142530-deploy --stop

# Bring the stack back on the version that matches the data
tale update --version 0.9.6
tale deploy --stop

The redeploy of the matching version is part of the restore, not an optional extra: the snapshot captured the data exactly as that platform version left it, and a newer binary would immediately re-run its migrations against it. The restore output prints the exact version recorded in the snapshot's manifest.

Restore drill

Run the drill quarterly on a non-production host. The drill is not "does a snapshot exist" — it is "can a fresh host be rebuilt from the off-host copy of the backups volume, the project workspace, and .env in under an hour." The failure modes the drill catches: an off-host job that never captured the workspace, and a stale .env that no longer matches the current binary's requirements.

Where this fits

Snapshots are the cheap part; the restore drill is what proves they work, and the redeploy-the-matching-version rule is the one thing to remember — recovery is never "roll the binary back," it is "restore the data and deploy the version it belongs to." The upgrade flow these snapshots protect lives in Upgrades; the hardening checklist that names backups as a row is in Hardening.

© 2026 Tale by Ruler GmbH — ISO 27001 & SOC 2 certified.

Tale is MIT licensed — free to use, modify, and distribute.