Backups workflow
This guide walks the everyday backup commands. The mental model behind them — what a backup contains per engine, the three trust states, what backups guarantee — lives in Backups (concept). Read that page first if any of those terms are new.
What you will learn
- How to create, list, verify, and download backups from the CLI
- How to restore a backup (engine-specific mechanics)
- The pre-destructive workflow pattern most projects need
- How to wire backups into CI before staged deploys
- How to read trust labels and recover when they say something is wrong
Prerequisites
- The Flux CLI installed and logged in (
flux login). - A project's
slugand seven-characterhashfromflux list(or aflux.jsoncarrying both — see Configuration). - Disk space for the artifact when you download —
pg_dump -Fcarchives are compressed but can still be substantial for active projects.
1) Create a backup
Both engines use the same command. The control plane runs pg_dump server-side and stores the artifact in its own backup volume:
flux backup create --project bloom-atelier --hash 0a1b2c3On v1 dedicated the artifact is the full project database. On v2 shared it is the tenant API schema only (pg_dump -Fc --schema=t_5ecfa3ab72d1_api --no-owner --no-acl). Both run in the same command shape; the engine determines the contents.
Creating a backup does not make it trustworthy. The fresh artifact is in the artifact validated state at best — the file exists and looks structurally fine. Promoting it to restore-verified is a separate step (see 3).
A common shortcut is to chain create and verify:
flux backup create --project bloom-atelier --hash 0a1b2c3 \ && flux backup verify --project bloom-atelier --hash 0a1b2c3 --latest
This is the single most useful one-liner before any destructive action.
2) List backups
flux backup list --project bloom-atelier --hash 0a1b2c3The output shows recent backups newest-first with their trust labels (per the three trust states). Common labels:
- Restorable — restore-verified, safe to act on.
- Created, not restore-verified — file exists and looks valid; nobody has tried to restore it yet.
- Restore verification failed — the artifact exists but
pg_restoredid not reproduce a usable database. Treat as broken. - Validating backup artifact — the upload finished moments ago and the validator is still catching up. Wait briefly and re-list.
- No backups — exactly what it says; create one.
Pass --verbose for catalog timestamps, artifact paths, and the underlying tier names. Useful when a label looks wrong and you need to trace it.
3) Verify a backup
This is the only step that promotes a backup to restorable. Verification runs pg_restore against the artifact in a disposable Postgres container on the control plane and checks that the schema and at least one non-system table came back:
flux backup verify --project bloom-atelier --hash 0a1b2c3 --latestVerify the latest with --latest, or a specific row with --id <backupId>. If verification fails, the row's trust label flips to Restore verification failed and the underlying error is recorded in the catalog — flux backup list --verbose will show it.
Restore verification is the contract. A backup that has never been verified is, operationally, not a backup yet. The pre-destructive pattern in Section 6 is built around this idea.
4) Download a backup
flux backup download --project bloom-atelier --hash 0a1b2c3 --latest -o ./bloom.dumpPass --latest (newest backup) or --id <backupId> (a specific row). The artifact is binary (pg_dump -Fc); the CLI refuses to write it to a terminal without -o or a redirect to avoid garbling the shell:
# Equivalent — redirect instead of -oflux backup download --project bloom-atelier --hash 0a1b2c3 --latest > ./bloom.dump
The downloaded file is a standard Postgres custom-format archive. pg_restore --list ./bloom.dump works against it without any Flux-specific tooling.
5) Restore a backup
There is no flux backup restore command today. Restoring is a two-step manual flow on both engines, deliberately so — the engines have different restore targets:
v1 dedicated — restore into the project's own Postgres
Get the project's Postgres connection string from the CLI:
flux project credentials bloom-atelier --hash 0a1b2c3# Copy the Postgres URI under the "Postgres" section.
Run pg_restore from your machine:
pg_restore --clean --if-exists --no-owner --no-acl \ --dbname "<paste Postgres URI>" \ ./bloom.dump
--clean --if-exists drops existing objects before recreating them. Skip those flags if you want to overlay onto an empty database instead.
v2 shared — restore into a Postgres you control
A v2 backup is a tenant export, not a shared-cluster restore. The intended targets are:
- A v1 dedicated stack you are migrating to (
flux migratedoes this for you — see Pooled → dedicated migrate). - Your own Postgres for archival, off-platform analysis, or running locally.
The restore is a normal pg_restore against any Postgres with the same major version; the dump is portable:
pg_restore --no-owner --no-acl \ --dbname "postgresql://user:pass@host/your_database" \ ./bloom.dump
The dump uses --no-owner --no-acl at create time, so role names and grants do not need to line up between the source tenant and the restore target. Re-create your application roles and grants in the target database before serving traffic.
6) Pre-destructive workflow pattern
The most common reason to use Flux backups in day-to-day work is "back up before doing something risky." The pattern is the same regardless of engine:
# 1. Create + verify in one shotflux backup create --project bloom-atelier --hash 0a1b2c3 \ && flux backup verify --project bloom-atelier --hash 0a1b2c3 --latest# 2. Confirm the latest is restore-verifiedflux backup list --project bloom-atelier --hash 0a1b2c3 | head -3# 3. Do the risky thing — apply a migration, drop a column, run a destructive scriptflux push ./db/migrations/0042_drop_legacy_table.sql# 4. If something is wrong, the verified backup is the recovery path
This pattern is the same one V1 dedicated quick SQL and Pooled → dedicated migrate link to. It is not engine-specific; it is destructive-action-specific.
flux nuke enforces the pattern by default — it refuses to remove a project unless the latest backup is restore-verified. The override (--skip-backup-check) exists for cases where you genuinely want to destroy without a recovery path; the warning text on stderr makes the choice explicit.
7) CI pattern: backup before staged deploy
Wiring this into CI is straightforward. The shape that works for most teams:
# Pseudocode — adapt to your CI runner- name: Backup production project run: | flux backup create --project ${{ vars.FLUX_PROJECT_SLUG }} --hash ${{ vars.FLUX_PROJECT_HASH }} flux backup verify --project ${{ vars.FLUX_PROJECT_SLUG }} --hash ${{ vars.FLUX_PROJECT_HASH }} --latest- name: Apply migrations run: flux push ./db/migrations/# If migration fails, the verified backup is recoverable.
Keep the API token used here narrow — read-write to the projects it touches, nothing more. See Project secrets.
Common pitfalls
| Symptom | Likely cause |
|---|---|
flux backup verify consistently fails | Postgres major-version mismatch between the verify image and the source; or the tenant schema was deleted between create and verify |
| List always shows "Validating backup artifact" | The validator is stalled or the upload truncated; re-create and watch --verbose for the artifact size |
| Download writes nothing to disk | Forgot -o or a shell redirect on a TTY (the CLI refuses binary to terminal) |
flux nuke refuses with "not restore-verified" | Latest backup is in a non-restorable trust state; create + verify, or pass --skip-backup-check if you really mean to destroy without a recovery path |
| Old backup artifact missing on disk | Retention swept it; older rows can have valid metadata but no file. Check the project's retention window in the dashboard |
The full symptom-by-symptom map for backup failures lives in Troubleshooting.
Next steps
- Backups (concept) — what backups guarantee and what they do not
- V1 dedicated quick SQL — pre-destructive pattern in context
- Pooled → dedicated migrate — how
flux migrateproduces and consumes backups - CLI reference — every backup flag in detail
- Troubleshooting — restore failures and the destructive-action gate