Backups
Create, list and restore database snapshots, and schedule them to run automatically.
Sp00ky Cloud takes care of your backups for you. Make a snapshot whenever you want, set up a schedule, and roll back to any backup when you need to.
Quick Start
Creating Backups
Make a backup of your database whenever you want one.
Backups run in the background. The CLI returns right away with a backup ID and a pending status. It moves to in_progress and then to completed once it’s done.
Listing Backups
You’ll see something like this:
Restoring from a Backup
Here’s what happens when you run it:
- The scheduler queues the restore and the CLI prints the restore ID.
- Ingestion stops. New writes get a
503, and proxy queries and SSP registrations are rejected while the restore is running. - Both databases are wiped and reloaded from the same backup file. Main SurrealDB and the scheduler’s snapshot replica stay in sync.
- Pending items are cleared. That covers the in-memory event buffer, the write-ahead log, and any per-SSP message buffers.
- Connected SSPs are evicted. They’ll re-register on their next heartbeat against the restored state.
- Sp00ky Cloud gives the restored database’s access methods new signing keys and checks that no forged token gets in (see Signing keys after a restore). Only then is the restore reported as done.
- The CLI polls for progress every 5 seconds (up to 5 minutes) and shows the current phase as it moves from
queuedtorunningtocompleted. - Once the restore finishes, your migrations run again against the restored database.
Restoring replaces your current data with the backup. Anything you wrote after the backup was taken is gone. If you’re not sure, take a fresh backup first.
Pay-as-you-go projects
A pay-as-you-go project has no scheduler, so Sp00ky Cloud takes and restores its backups itself, with the same commands and the same backup files. A restore wipes the database, imports the backup and reloads the sync engine, which picks up the restored data on its own; run your migrations again afterwards as above.
To change SurrealDB version, use spky db upgrade, not a backup and restore: it keeps everyone signed in, and takes a backup of its own first.
Signing keys after a restore
Every restore, on VMs and on pay as you go, gives each record DEFINE ACCESS a new signing key, so everyone signed in has to sign in again. SurrealDB’s export does not contain the keys (it writes '[REDACTED]'), and a database restored with that placeholder would let anyone sign a valid token for any user. Sp00ky Cloud checks the restored database after every restore, whatever scheduler version imported it, and refuses to report a restore as done until no access accepts such a token.
Two kinds of access cannot get their key back. Admin impersonation (_00_impersonate) works again after your next spky deploy, which sets its key. An access that verifies tokens of an outside issuer with a shared key is removed by the restore: run its DEFINE ACCESS statement again afterwards (the restore’s metadata names it).
If the main database gets wiped but the snapshot replica fails to import, the scheduler stays in the restoring state on purpose. That blocks reads until someone re-runs the restore. Serving traffic from a half-restored cluster would give back wrong data.
From the dashboard
The scheduler’s admin dashboard has a Backups tab that does everything above except reset: create, list, restore, delete and configure the schedule. It shows the same catalog as spky backup list, joined to what the scheduler itself knows about each backup, and a restore there reports the real stages as the scheduler moves through them (queued, running, main database restored, replica restored, done). It goes through Sp00ky Cloud like spky backup restore, so the signing keys are renewed the same way, and migrations still have to be run again afterwards.
How the dashboard talks to Sp00ky Cloud. The control plane injects SPKY_CLOUD_API_URL and SPKY_CLOUD_PROJECT into the scheduler container (only the scheduler, never the SSPs). The scheduler then calls an allow-listed route family, /v1/internal/projects/{slug}/… (restart, deployment status, and the backup routes minus reset), authenticated with the project’s existing SPKY_AUTH_SECRET. No new credential is created. A control plane that supports this lists scheduler_link under features in its /health response; a scheduler without the link still works and marks those actions as unavailable.
If a backup started from the dashboard fails with Sp00ky Cloud rejected this
scheduler’s credentials, that is the control plane refusing the scheduler’s
SPKY_AUTH_SECRET, not your login expiring. The dashboard reports it as a
502 carrying the code cloud_auth and keeps you signed in, precisely so the
real cause is visible; an earlier version relayed the upstream 401 and
signed the operator out instead, which hid it. Check that the project still
has a stored auth secret and that the scheduler container was recreated since
the secret last changed, then retry. The catalog degrades the same way rather
than disappearing: the Backups tab still loads and shows the message where the
list would be.
Deleting Backups
Backups belong to their project: destroying the project deletes all of them.
Automatic Backups
Set up a schedule with a cron expression:
| Option | What it does |
|---|---|
--enabled | Turn automatic backups on or off (true/false) |
--schedule | Cron expression for how often to back up (e.g. "0 2 * * *" for daily at 2 AM) |
--retention | How many backups to keep before the oldest ones get deleted |
A pay-as-you-go project is backed up every day at 03:00 UTC and keeps the last 7, until you configure backups yourself. Scheduled backups pause while a project is stopped at its spend cap.
Database Reset
Reset your database to a clean slate. This drops all data and re-runs your migrations.
The CLI will:
- Warn you that all data will be deleted.
- Ask you to confirm.
- Offer to create a backup first (a good idea).
- Wait for that backup to finish if you said yes.
- Reset the database and re-apply your migrations.
To skip the pre-reset backup prompt:
There’s no undo for a reset. Every user, every record, every bit of app data goes away for good. Always take a backup first unless this is a dev project you don’t care about.