Your box. Your control plane.

One script on a Linux machine installs an edge with automatic TLS, a sandbox, a control plane, a dashboard and the runtime. Your source stays on your laptop; only the compiled binary is uploaded.

Alpha. It runs this website and holds real deployments, but the storage format and the CLI contract can still change between minor versions.

HTTPS traffica hostname per app, certificates handled

Your Linux box

blog

sprout v3

its data

KVR2

api

sprout v7

its data

D1Queue

shop

sprout v2

its data

KVD1R2
Control plane deploy, rollback, logs, dashboard
A deploy uploads one compiled binary and makes it the active version. Older versions are kept, so a rollback is one command. KV, D1, R2 and queue data lives in resources that outlive every version. Deploy lifecycle

Install in four steps

A Linux box, a domain pointed at it, and the CLI on your laptop.

  1. 1

    Get a Linux box

    A Linux VPS or home server with a domain you control. Check the installation requirements before choosing a machine.

  2. 2

    Run the installer

    It provisions Caddy with automatic TLS, a bubblewrap sandbox, a firewall, one admin identity, and the control, edge and dashboard services. It pauses once so you can add a DNS record.

    $ curl -fsSL https://sproutboat.com/install.sh | sudo bash
  3. 3

    Point the CLI at your endpoint

    A device-code browser flow, or the admin token the installer printed. The CLI keeps credentials per endpoint, so you can hold several.

    $ sproutboat login --api-url https://sproutboat.your-domain.com
  4. 4

    Deploy

    Porffor compiles your handler on your machine. The CLI uploads only the binary; your node runs it behind Caddy. From here on it is just sproutboat deploy.

    $ sproutboat deploy

Supported bindings

What a deployment gets on a self-hosted node. Each example is a runnable project.

BindingWhat it isExample
Handlers export default { fetch }: one request in, one Response out hello
KV key-value store: get / put / delete / list kv
D1 SQL database: prepared statements, batch, transactions d1
R21 S3-style object storage with sha256 etags r2
Queues a producer handle plus a queue(batch) consumer, with retries queue
Durable Objects2 addressable single-threaded instances, each with its own storageIncludes alarms: setAlarm / getAlarm / deleteAlarm and the alarm() handler. durable-object
Cron triggers scheduled(event), fired on cron expressions cron
Static assets files served from a directory via env.ASSETS.fetch() assets
Analytics Engine writeDataPoint() and query() analytics
Rate limiting3 env.NAME.limit({ key }) -> { success }, a fixed window per key ratelimit
Vars & secrets config values, and secrets that never enter the binary vars-secrets
Outbound fetch fetch() to an allowlisted host, http and https outbound-fetch
Service bindings env.PEER.fetch() to another deployment on the same nodeA service call routes through the node's edge, which a single binary does not have. service-bindings
ctx.waitUntil4 work that outlives the response, on fetch/scheduled/queue waituntil
Streams5Not supported ReadableStream / WritableStream, and streaming response bodies -
  1. An object is held whole in memory both ways. Keep them small for now; see the note in the docs.
  2. An alarm is not yet guaranteed to avoid running alongside a request to the same object.
  3. One node uses a fixed window; requests near a window boundary can exceed the intended per-interval rate.
  4. In-process drain, capped at 25s.
  5. Blocked upstream in Porffor (issue #349); a response body is a whole string today.

Don't want to run it?

A managed Sproutboat is coming: the CLI ships with a default endpoint, sproutboat deploy just works, and you never touch a VPS. Same Porffor binaries, same env.* bindings; you skip the operations. One email when it opens, nothing else.

One email when it opens. Nothing else.