How it worksCLICloud and CommunityikadaDocsGitHub
How it works

From fetch handler to native binary.

Sproutboat takes a Cloudflare Workers handler, compiles it ahead of time with Porffor, and runs the result as a native process. On Sproutboat Cloud the compile happens on our build servers. Here is each step, what runs where, and what is supported.

  1. 01

    Write a handler

    The Workers module shape: export default { fetch }, plus scheduled and queue if you need them. Bindings are declared in sproutboat.jsonc.

    {
      "name": "notes",
      "main": "src/index.js",
      "compatibility_date": "2026-09-07",
      "kv_namespaces": ["NOTES"]
    }
  2. 02

    Bundle and upload

    npx sproutboat deploy bundles your handler and uploads the bundle, usually a few kilobytes. Bindings without an id get their own storage on the first deploy, and the id is written back to sproutboat.jsonc.

    ✓ provisioned kv notes-notes → kv_4f1c9a20b7e3
    ✓ bundled notes · 1.2 KB
    ✓ uploaded the bundle to Sproutboat Cloud
  3. 03

    Build on Sproutboat

    Our build servers compile the bundle ahead of time with Porffor into native code: no JIT, no engine to start. Each result is cached by a hash of its input, so the same input is never compiled twice.

    Community and standalone builds run the same compiler on your own machine.

    ✓ built on Sproutboat
      input 7c1e9a04: cache miss, compiled
    # deploy the same input again:
      input 7c1e9a04: cache hit, reused
  4. 04

    Serve

    On Cloud the app answers at <app>.<account>.sproutboat.app, and custom domains are free. Every deploy is a new version you can roll back to.

    🌱 Deployed notes
      https://notes.acme.sproutboat.app
      version 3f9c2a71
  5. 05

    Run it three ways

    Cloud runs your apps on sproutd, our own runtime: each app in its own sandbox, asleep when idle and awake again on the next request. Community runs your apps on one machine you own. A standalone binary carries its bindings, SQLite and TLS inside one executable.

    sproutboat deploy              # Cloud or Community
    sproutboat build --standalone  # one executable

What happens to a request.

Every app on Sproutboat Cloud is its own sandboxed process. An idle one sleeps, so a quiet app costs almost nothing, and the next request wakes it.

HTTPSnotes.acme.sproutboat.app
EdgeTerminates TLS and routes by hostname.
sproutdWakes the app if it is asleep.
notesIts own process and sandbox. Answers the request.
A sleeping app wakes in a few milliseconds, typically 5 to 8 ms in our early measurements.

Bindings, and their limits.

Cloud and Community run the same deployments, so they share a column. Every row has an example the CLI builds and calls, except service bindings, which need two deployments.

BindingCloud and CommunityStandalone binary
Handlersexport default { fetch }: one request in, one Response out SupportedSupported
KVkey-value store: get / put / delete / list SupportedSupported
D1SQL database: prepared statements, batch, transactions SupportedSupported
R2 1S3-style object storage with sha256 etags SupportedSupported
Queuesa producer handle plus a queue(batch) consumer, with retries SupportedSupported
Durable Objects 2addressable single-threaded instances, each with its own storage SupportedSupported
Cron triggersscheduled(event), fired on cron expressions SupportedSupported
Static assets 3files served from a directory via env.ASSETS.fetch() SupportedSupported
Analytics EnginewriteDataPoint() and query() SupportedSupported
Rate limiting 4env.NAME.limit({ key }) -> { success }, a fixed window per key SupportedSupported
Vars & secretsconfig values, and secrets that never enter the binary SupportedSupported
Outbound fetchfetch() to an allowlisted host, http and https SupportedSupported
Service bindingsenv.PEER.fetch() to another deployment on the same node SupportedNot supported
ctx.waitUntil 5work that outlives the response, on fetch/scheduled/queue SupportedSupported
Streams 6ReadableStream, WritableStream, TransformStream, and response bodies streamed as they are written SupportedSupported
HTMLRewriter 7Rewrite HTML responses with element, text, comment and document handlers SupportedSupported
Compression streamsCompressionStream and DecompressionStream: gzip, deflate, deflate-raw SupportedSupported
  1. 1. R2: An object is held whole in memory both ways. Keep them small for now; see the note in the docs. Read the docs
  2. 2. Durable Objects: An alarm is not yet guaranteed to avoid running alongside a request to the same object. Read the docs
  3. 3. Static assets: Compiled into a standalone binary, capped at 8 MB. Read the docs
  4. 4. Rate limiting: One node uses a fixed window; requests near a window boundary can exceed the intended per-interval rate. Read the docs
  5. 5. ctx.waitUntil: In-process drain, capped at 25s.
  6. 6. Streams: Request bodies are still read whole (up to 1 MiB).
  7. 7. HTMLRewriter: Rewrites the whole body at once rather than streaming it; no :nth-child-style pseudo-classes.

Examples live in sproutboat-cli/examples.

The same Worker on three runtimes.

A standalone sprout next to workerd and Node, with the raw samples published.

NodeworkerdSproutboat
Idle memory (PSS)52.3 MiB46.5 MiB7.44 MiB
Start to first correct response247.7 ms53.6 ms12.0 ms
p95 latency, JSON orders5.51 ms5.29 ms2.58 ms
p95 latency, 10% wait on a 50 ms upstream55.2 ms53.65 ms56.81 ms
CPU time per 1,000 requests2,585 ms1,654 ms1,159 ms

The same Worker-style app on Node, workerd and a Sproutboat v0.18.0 executable on one Linux host, medians of 3 rounds at 50 requests/s, 2026-10-20 (raw samples and method). On CPU-heavy code, workerd’s JIT is still about 5× faster in our early sproutd tests.

Sproutboat Cloud is in closed alpha.

Join the waitlist and we’ll send one email when your invite is ready. Nothing else.

One email when your invite is ready. Nothing else.

You’re on the list.

We’ll email you once, when your invite is ready.