Configuration
Sp00ky has two configuration surfaces. sp00ky.yml lives at your project root and is read by the spky CLI to provision SurrealDB, the SSP, codegen, and your apps. SyncedDbConfig lives in your client app and is passed to new SyncedDb(...) to customize logging, persistence, and sync timings.
The sp00ky.yml file
sp00ky.yml is the single source of truth for the spky CLI: it tells spky dev, spky deploy, and spky doctor how to run your stack, which SurrealDB version to spin up, where your schema and buckets live, which client types to generate, and how your frontend and backend apps boot. Run spky doctor at any time to validate the file.
Add the schema comment as the first line of sp00ky.yml to get autocomplete and validation in editors that support yaml-language-server:
Minimal example
The smallest viable file to get spky dev running:
For a fully annotated reference covering every option, see example/sp00ky.yml in the repo.
Top-level settings
| Field | Type | Default | Purpose |
|---|---|---|---|
mode | singlenode | cluster | surrealism | singlenode | Deployment topology. singlenode runs one SSP, cluster runs multiple, surrealism is for embedded setups. |
slug | string | (none) | Project slug used by spky deploy and the other cloud commands. |
surrealdb | object | (none) | DB connection. Sub-fields: namespace, database, username, password, hosting (cloud or external), endpoint (required when hosting: external). |
schema | path | (none) | Directory containing your .surql schema sources. See Schema. |
buckets | path[] | [] | Bucket definition files referenced from your schema. See Buckets. |
clientTypes | array | [] | Codegen targets. Each entry has format (typescript or dart), an output path, and (dart only) an optional workdir. See Client types. |
version | string | object | latest stable | Pin SSP and scheduler image tags. Accepts a single tag, a {dev, cloud} split, or a path: override pointing at a local binary. |
logLevel | string | object | info | Log verbosity. Accepts trace, debug, info, warn, error, off, target=level directives, or a {dev, cloud} split. |
refMode | dedicated | single | dedicated | Storage layout for the SSP’s _00_list_ref table. dedicated gives each user their own table and works around a SurrealDB v3 LIVE-permission gap. |
apps | map | {} | Your frontend and backend services. See Apps below. |
deployment | object | (none) | Cloud deployment knobs: sspCount, backup. See Cloud Deployment. |
Apps
Each entry under apps is a service spky knows how to run locally and deploy to the cloud. Set type: frontend, type: backend, or type: docker, then describe how it boots (dev) and how it deploys (deploy). Backends additionally need an OpenAPI spec, a baseUrl, an optional auth block, and a method (typically outbox) so the SSP can deliver jobs.
dev accepts either a raw command string or a typed form: {type: npm, script, workdir?}, {type: docker, file, workdir?, port?} (builds a Dockerfile for this app’s dev server), or {type: uv, script, workdir?}. deploy accepts dockerfile, context, port, healthcheck, resources (vcpus, memory, disk), and a timeout.
scope — where an app runs
Every app accepts an optional scope controlling where it runs:
scope | Behavior |
|---|---|
all (default) | Started by spky dev and deployed to the cloud. |
devOnly | Local-only — started by spky dev, never deployed. Validation is relaxed (no spec/method/deploy required), so it’s handy for a local sidecar. |
cloudOnly | Deployed to the cloud but skipped by spky dev. |
type: docker — run a prebuilt image
A docker app runs a prebuilt image directly (no Dockerfile build) — useful for local infra like a LiveKit SFU, a mock service, or a cache. Fields:
image(required) — the image to run, e.g.livekit/livekit-server:latest.ports— published ports. A bare port (7880) maps host→container 1:1 (7880:7880); use"host:container"to remap and a/protosuffix for UDP ("7882/udp").args— appended after the image as the container command (e.g.["--dev"], or["go", "run", "."]to run a service from source).volumes— bind/volume mounts (docker run -v), e.g.["/var/run/docker.sock:/var/run/docker.sock", "${PROJECT_DIR}/../..:/src", "gomod:/go"].${PROJECT_DIR}(the absolute directory ofsp00ky.yml) is expanded in the host portion.workdir— working directory inside the container (docker run -w).dependsOn— names of otherdockerapps that must be ready before this one starts.spky devlaunches apps in dependency order; an unknown name, a self-dependency, or a cycle is rejected at config load (caught byspky lint/spky doctor).healthcheck— an HTTP path (e.g./health) polled on the app’s first published host port until it returns 200. AdependsOnwaits for this — i.e. for the service to be genuinely up, not just for the container to have started. Without it, a dependency is “ready” as soon as its container is running.
Under spky dev it runs as the container sp00ky-dev-<name> on the dev network (reachable from sibling apps by its name) with --rm teardown. ${PROJECT_DIR} is also expanded in env values, and user env overrides the auto-injected SPKY_* vars. With scope left as all/cloudOnly, deploys pull the image and ship it through the same image pipeline as a backend; pair it with scope: devOnly for a purely local service (dependsOn/healthcheck are spky dev-only). env (below) is passed through as container environment variables.
For per-app environment variables (env: { dev, cloud, vault }), see Environment Variables.
Client types
clientTypes is a list of codegen targets; spky generate (run with no args) regenerates every entry from your schema. Each entry has a format and an output path (relative to sp00ky.yml):
typescript— the CLI’s built-in generator emits a typed schema module (e.g.schema.gen.ts).dart— runs spooky_core’s richer generator (dart run spooky_core:spooky_gen), which emits the typed client,Patchclasses, andspookySchema/surqlSchema. Because that tool resolvesspooky_corefrom the enclosing Dart package, it runs from the package directory — auto-derived fromoutput’s nearest ancestorpubspec.yaml. Set the optionalworkdironly to override that. (This replaces a manualdart run spooky_core:spooky_gen/ Makefile step.)
A project can list several outputs — e.g. a TypeScript web client plus one or more Dart clients (a Flutter app, a renderer) — and keep them all in sync from one command.
Per-environment overrides
version, logLevel, and apps.<name>.env each accept a {dev, cloud} split so your local stack can differ from what runs in Sp00ky Cloud. A common pattern is to run host-built binaries during spky dev and a pinned image tag in the cloud:
Client SDK (SyncedDbConfig)
SyncedDbConfig (sometimes referred to as Sp00kyConfig in older docs) is the object you pass to new SyncedDb(...) in your client app to customize logging, persistence, and sync timings.
Configuration Interface
Example Configuration
Options Detail
database.endpoint
The WebSocket URL for your SurrealDB instance (e.g., ws://localhost:8666/rpc when running locally with the Sp00ky CLI’s bundled dev stack). The Sp00ky client connects directly to the database. Optional, and when omitted the client connects in offline-only mode and queues mutations until a remote is configured.
database.store
'indexeddb'(default): Persistent local storage in the browser'memory': Transient in-memory storage (clears on page reload)
logLevel
Controls the verbosity of logging output:
'trace': Most verbose, includes all internal operations'debug': Detailed debugging information'info': General lifecycle events (connected, synced)'warn': Recoverable errors and warnings'error': Critical failures'fatal': Fatal errors that stop execution
persistenceClient
Determines where metadata like query states are persisted:
'surrealdb'(default): Store in the local SurrealDB instance'localstorage': Use browser localStorage- Custom implementation of
PersistenceClientinterface
streamDebounceTime
Window (ms) the client-side Stream Processor uses to coalesce DBSP
stream updates per query before they fan out to useQuery
subscribers — so a burst of synced records (e.g. the initial library
sync) repaints affected views once per window instead of row-by-row.
Lower values feel snappier; higher values reduce re-render thrash on
bursty writes. Defaults to 50.
crdtDebounceMs
Window (ms) used to coalesce CRDT field UPSERTs to upstream. Local
writes are applied to the LoroDoc immediately on every keystroke
(so reload and offline work), but the remote _00_crdt UPSERT is
debounced. Defaults to 500.
refSyncIntervalMs
Cadence (ms) for the _00_list_ref poll that catches cross-session
UPDATEs that the SurrealDB v3 LIVE-permission gap drops. Defaults
to 500; non-positive values fall back to the default. The poll
self-throttles to a longer interval when LIVE is delivering events
healthily (see Architecture).
Diagnostics
The client exposes a small number of read-only getters intended for e2e regression guards and runtime instrumentation.
pendingMutationCount and subscribeToPendingMutations
Live count of mutations queued for upstream sync. The subscribe variant fires on enqueue/dequeue so a UI can render a “saving…” indicator without polling.
liveRetryCount
Number of times the initial _00_list_ref[_user_*] LIVE SELECT
subscription had to retry on the most recent setCurrentUserId
call. Stays at 0 when the SSP’s pre-emptive per-user table
creation got there first (the default path); a value above 0
means the LIVE registration hit a “table not found” race and the
client fell through to the poll fallback while retrying. The e2e
suite’s z-auth-bootstrap.spec.ts asserts this stays 0 after a
clean signup so the pre-emptive path can’t silently regress.