Walwarden Docs
Restore

Restore walkthrough

Step-by-step: from the dashboard CTA to a completed restore with JSONL output.

Before you start

  • pg_restore on the restore machine must match the major version of the source database. Check: pg_restore --version. If there is a mismatch, see Install the CLI.
  • The restore machine must have network access to the target database.
  • You need a target Postgres database to restore into. For new_database mode, the target can be any Postgres cluster — walwarden will create a new database inside it. For in_place mode, the target database must already exist and you must accept that it will be overwritten.

Step 1: Click "Restore from this backup"

Navigate to the database detail page for the source database. In the Backup history table, find the backup you want to restore from and click Restore from this backup.

A modal appears with a mode picker:

  • New database (default) — walwarden creates a new database on the target cluster using the source database name. The target cluster must not already have a database with that name, or the restore will fail. Use this for test restores, cloning, and migrations.
  • In-place — walwarden overwrites an existing database on the target. The target database must already exist. A destructive-intent warning is shown. Selecting in-place enables a checkbox: "I understand this will overwrite the target database." The Issue restore token button is disabled until you check it.

Select your mode and click Issue restore token.

Step 2: Copy the one-liner

The modal is replaced by the one-liner panel. The full command looks like:

WALWARDEN_TOKEN=<token> npx --yes walwarden-cli restore \
  --manifest <sha256> \
  --target '<paste-target-dsn-here>' \
  --mode new_database

Click Copy to copy it to the clipboard.

The panel shows an expiration countdown. Restore tokens are valid for 1 hour. If the token expires before you run the command, issue a new one from the same backup row.

Step 3: Fill in the target DSN and run

On the restore machine, paste the command and replace <paste-target-dsn-here> with your target Postgres DSN:

WALWARDEN_TOKEN=<token> npx --yes walwarden-cli restore \
  --manifest <sha256> \
  --target 'postgresql://user:password@host:5432/postgres' \
  --mode new_database

If you prefer not to put the password inline, omit it from the DSN and set PGPASSWORD:

export PGPASSWORD='your-password'
WALWARDEN_TOKEN=<token> npx --yes walwarden-cli restore \
  --manifest <sha256> \
  --target 'postgresql://user@host:5432/postgres' \
  --mode new_database

Run the command.

What happens next

The CLI prints a rich progress view in a TTY, or JSONL events if stdout is not a TTY or --json is passed. A successful run produces output like:

phase: download      bytes: 142MB / 142MB   elapsed: 8.2s
phase: verify        checksum: ok           elapsed: 0.3s
phase: restore       pg_restore: running    elapsed: 4.1s
phase: finalize      state: completed       exit: 0

In JSONL mode (or if you pass --json):

{"state":"downloading","at":"2026-05-26T14:32:00.001Z","payload":{}}
{"state":"verifying","at":"2026-05-26T14:32:08.412Z","payload":{}}
{"state":"manifest_verified","at":"2026-05-26T14:32:08.723Z","payload":{"checksumSha256":"<hash>"}}
{"state":"restoring","at":"2026-05-26T14:32:08.800Z","payload":{}}
{"state":"finalizing","at":"2026-05-26T14:32:12.901Z","payload":{}}
{"state":"completed","at":"2026-05-26T14:32:13.001Z","payload":{"bytesRestored":148897024,"checksumSha256":"<hash>"}}

The CLI exits 0. The restore token is now invalidated; it cannot be reused.

Step 4: Verify in the dashboard

Return to the dashboard database detail page. The Restore history section shows the completed restore job with its full state timeline, the manifest hash, and the bytes transferred.

If the restore failed, the timeline shows the failure state and classification. See Troubleshooting.

Connect to the target database and confirm the expected tables and row counts are present:

psql 'postgresql://user:password@host:5432/restored-db-name' -c "\dt"

For a new_database restore, the database was created with the source database name. Connect to that database name on the target cluster.

A backup you have not verified by connecting to the restored database is a backup you have not fully proven. Even spot-checking one table count is better than no check.