Deploying
One command builds your images, provisions infrastructure, runs migrations and cuts over DNS.
Deploy
The deploy command performs these steps automatically:
- Validates your
sp00ky.ymlconfiguration - Builds Docker images for each app (linux/amd64)
- Uploads images to Sp00ky Cloud (skips unchanged images)
- Provisions infrastructure (SurrealDB, Scheduler, SSP instances)
- Runs migrations against the cloud database
- Deploys your backend and frontend containers
- Configures DNS and SSL certificates
You’ll see real-time progress as each step completes.
Run spky lint before deploying to catch config issues early.
Flags
| Flag | Effect |
|---|---|
--upgrade | Also move the SSP and Scheduler to the newest published build. Only for a project whose version is any or unset: a pinned version stays where sp00ky.yml put it, and newest already rolls on every deploy. |
--only api,web | Build and deploy just these apps. Everything else keeps running untouched. |
--clean | Wipe the scheduler’s persistent volume first. Last resort: the scheduler self-heals stale snapshot state on startup, and spky verify --fix (or POST /admin/resync on the scheduler) repairs it without a wipe. Your SurrealDB data is not touched either way. |
--force-schema | Re-apply the internal schema and remote functions even when the hash says nothing changed. Drift recovery. |
--cache-bust | Clients reloading onto this version clear service-worker caches first. |
--mandatory | Clients reload immediately instead of being offered a notification. Broken-build kill switch. |
--only is the one to reach for during normal iteration: a frontend-only change doesn’t need the
backend rebuilt.
A backend on a dedicated machine shows up in the deploy table as
machine/<name> with its public address, moving through creating, booting and serving. A
deploy of such a backend takes a few minutes longer: a fresh VM boots beside the old one and only
takes over once it answers its healthcheck.
Checking Status
Shows the current deployment version, status, and all running VMs with their roles and versions.
The operator dashboard
Every deployment also serves a dashboard in the browser, at
https://<slug>-admin.<domain>/admin. spky status prints the URL alongside the
others.
It is the same information spky status and spky logs give you, live and
without a terminal: scheduler and SSP health, end-to-end sync latency, backend
health, workflow runs as they happen, and a live log tail. It also carries the
actions, so you can restart an SSP, retry a failed workflow run, take a backup or
upgrade images from the browser.
Nobody can sign in until you grant someone access with spky admin add <user>.
See the admin dashboard for sign-in, the
actions and their consequences, and the
MCP server it serves for AI agents.
Scaling
Scale your SSP instances horizontally:
You can also set the default SSP count in your sp00ky.yml:
Infrastructure Environment Variables
Backends read their environment from the encrypted vault (spky env set). The
infrastructure containers Sp00ky Cloud owns — SSP, Scheduler, SurrealDB — take a
fixed environment assembled by the control plane. deployment.env is the escape
hatch for setting a runtime knob on them, per role and per project:
These are not secrets. Unlike spky env set, values are stored
unencrypted in the project’s cloud config. Put credentials in the vault, not here.
Keys the control plane manages itself are refused rather than silently
overridden: SPKY_DB_*, SPKY_AUTH_SECRET, SPKY_SCHEDULER_URL,
SPKY_SSP_ID, SPKY_SSP_ADVERTISE_ADDR, the SSP snapshot/arena directories,
SPKY_JOB_CONFIG, and S3_*. Those carry credentials, per-slot identity, or
values derived from your deployed backends — overriding them breaks the
deployment in ways that are hard to see (a stale SPKY_JOB_CONFIG disables job
routing while health checks still pass).
Values take effect when containers are next created, so run spky deploy or
spky restart after changing them. Omitting the key entirely keeps the previous
setting; an explicit empty map clears it.
deployment.env, the sync: block and the top-level anonymousLiveQueries
are read from sp00ky.yml on every deploy, whether spky deploy runs it or a
git-linked build does. Both paths write the same values,
so a push after a CLI deploy never reverts them.
One pair is set for you: with sync.transport: changefeed in sp00ky.yml,
spky deploy merges SPKY_INGEST_TRANSPORT and SPKY_CHANGEFEED_RETENTION
into the scheduler and ssp roles (your own keys win on a clash), so the
scheduler tails the feed the schema just gained. See
Sync transport. Likewise, with
sync.queryAllowlist set to warn or enforce, spky deploy merges
SPKY_SSP_QUERY_ALLOWLIST=<mode> into the ssp role and publishes the committed allowlist JSON
as _00_query_allowlist rows keyed by the frontend’s package.json version; under enforce a
missing or stale JSON fails the deploy. See the
Query allowlist guide.
SPKY_SSP_DB_TIMEOUT_SECS is the knob most worth knowing here: it bounds how
long a single SSP database call may take before it fails and the connection is
rebuilt (default 15s, 0 disables). It exists because the SurrealDB HTTP
engine has no request timeout of its own and every SSP database call shares one
connection, so an unbounded stall parks every route that touches the database.
See environment variables and
GET /health.
Log Level
logLevel in sp00ky.yml sets RUST_LOG on the Scheduler and SSP containers. Default is info.
Use a { dev, cloud } map to differ per environment:
The value is forwarded to tracing-subscriber, so target-specific directives work:
Each spky deploy sends the resolved cloud value to Sp00ky Cloud, which restarts the Scheduler and SSP containers with the new RUST_LOG. Use --upgrade if you also want the newest SSP and Scheduler build at the same time (it does not move a pinned version).
At trace, the Scheduler logs every replica query and every record it ingests during bootstrap. Useful for diagnosing “why isn’t this row showing up?” See Logs & Monitoring.