snoozestackdocs

The runtime

Everything your project's backend does — running functions, holding the database, storing files, working queues, firing schedules, recording signals, serving sites, verifying who's calling — is one self-contained service: the snoozestack runtime. snoozestack dev runs it on your machine as a single native process, and snoozestack publish runs the same thing on managed hosts. There is no separate database server, auth container, or job worker to assemble; the runtime is the whole anatomy.

Why one service

A conventional backend is a committee: a database here, an auth service there, a job runner, an object store, and a pile of configuration wiring them together — which is why “works on my machine” and “works in production” are usually two different claims. Making the whole backend one process makes the two claims the same one: what your laptop runs and what the hosted fleet runs are the same code path, differing only in configuration.

It also makes the project portable. The runtime reads your committed snoozestack/ folder and keeps all of its state under one directory — so moving, replicating, or throwing away a backend is moving, replicating, or throwing away a folder, not an infrastructure migration.

The layers, bottom up#

Data. The base of the stack is what the runtime owns on disk: a database built from your committed schema, one directory per declared storage bucket, and the signals store. All of it lives under .snoozestack/ — locally that's a folder you can delete to start fresh (snoozestack dev reset); hosted it's a volume that is continuously replicated to durable storage.

Functions. Above the state sits the only code that can touch it: functions you commit, on one contract — export default (req, capabilities). Every entry point lands here: an HTTP call from your app, a queue message, a cron schedule, a webhook, an MCP tool call. There is no client-facing route to the database at all.

Capabilities. The seam between those two layers is explicit: a function declares in project.toml which capabilities it may use — db, storage, auth, signals, push, secrets — and receives exactly those as its second argument. An undeclared capability isn't forbidden at runtime; it simply isn't there. See Permissions.

Identity. The one thing deliberately outside the runtime. Sign-in — magic link, Google, Apple, email/password — runs on snoozestack's central identity plane, because OAuth callbacks, email delivery, and password hardening belong on stable hosted infrastructure, not in every laptop and container. What the runtime holds is verification: sessions are signed tokens, and the runtime checks the signature locally — offline, per request, no round trip — after fetching the project's public key once. See Authentication.

App. The surface your users actually meet. Declared sites are served by the same process locally, next to the functions they call, and publish as immutable versions hosted; a custom domain fronts the same content; the SDKs your app is built with call in; and what happens out there comes back as Signals.

Agents. Because the project is files and the operations are explicit commands, the whole lifecycle is drivable by more than hands: the CLI for you and CI, the management API for scripts, and MCP for AI clients — all reading and writing the same project model, never a hidden setting.

One process, three places#

WhereHow it startsWhat's different
snoozestack devIn-process, native — no DockerWatches your files, serves the local dashboard, seeds fresh databases, and provides a built-in dev sign-in account
Dockerdocker run … snoozestack-runtimeHeadless: same engine, configured by environment variables
Hostedsnoozestack publishOne container per project and namespace; state replicated continuously; watcher, dashboard, seed, and dev account off

The differences are configuration, not forks — hosted mode is the same engine with the development conveniences turned off and durability turned on. That's the property the rest of the docs lean on: if it worked under snoozestack dev, publishing doesn't change what runs, only where.

Running it in Docker yourself#

The hosted cloud is the managed way to run the runtime, but it isn't the only way — the same image runs anywhere Docker does, configured entirely by environment:

terminal
docker run --rm -p 8787:8787 \
-v /path/to/your-app:/project \
-e RUNTIME_PROJECT_DIR=/project \
snoozestack-runtime
VariableMeaning
RUNTIME_PROJECT_DIRThe checkout containing snoozestack/ (required)
RUNTIME_PORTListen port, default 8787
RUNTIME_MODEhosted (default) or dev — dev adds the watcher, dashboard, and dev account
RUNTIME_SECRETS_FILEA mounted JSON name→value map — secret values are never baked into the image
RUNTIME_PROJECT_URL / _REF / RUNTIME_API_KEYWhere to fetch the project's session-verification key; unset means anonymous-only, and auth = "required" routes answer 401

The isolation model#

Hosted, each project×namespace gets its own container, and the container boundary is the tenant boundary: a runtime is scoped to exactly one app, capabilities are the only path from function code to data and secrets, and the blast radius of anything a function does is its own container. Namespaces — dev locally, default (live) and named previews hosted — each hold genuinely separate state, which is what lets you exercise a preview without touching live data.