Documentation
ReferenceArchitecture

The Firecracker runtime

Every Tabbify app runs as a detached runner process hosted by a supervisor. What that runner does inside is boot a Firecracker microVM built from your OCI image — and that is the one and only runtime Tabbify ships. You don't pick a runtime; there's nothing to choose.

One runtime: Firecracker

Your Dockerfile is built into an OCI image, that image is unpacked into an ext4 rootfs, and Firecracker boots a microVM that runs the image's entrypoint. Each app gets its own kernel and rootfs, so apps are isolated from each other and from the host at the VM level. Firecracker only runs on a Linux supervisor with /dev/kvm — on a host without KVM, placement fails by design (see Capability detection below).

This single-runtime model is intentional. There is no in-process WASM runtime and no bare-container runtime to weigh against it: the build always produces an OCI image, and the OCI image always runs as a Firecracker microVM. A first request after a deploy (or after a long idle) waits a moment while the VM boots; every request after that is fast.

A note on legacy tabbify.toml fields

Older tabbify.toml files sometimes carried a [runtime] type = "..." value or a per-deploy runtime = "..." override (for example "wasm-http" or "docker"). Those keys are tolerated for wire-compatibility and ignored — they no longer select anything. Whatever they say, the app builds an OCI image and runs as Firecracker. You can leave them in an old manifest, but new manifests should omit them.

Likewise, [build].kind is always docker (build the Dockerfile into an OCI image). It controls the artifact, not the runtime.

What [runtime] actually configures

The [runtime] section sets the microVM's lifecycle and resource limits — not a runtime choice. See the tabbify.toml manifest for the full schema.

[runtime]
lifecycle        = "on_request"  # always_on | on_request
idle_timeout_sec = 300
memory_mb        = 512
vcpus            = 1
  • lifecyclealways_on keeps the VM running; on_request starts it on the first visit and stops it after idle_timeout_sec of inactivity.
  • memory_mb / vcpus — the microVM's memory and CPU allocation.

Capability detection

A supervisor only advertises what it can actually host. It adds the firecracker tag if /dev/kvm is readable, the docker tag if a Docker daemon is reachable (used for building images), and the builder tag if the operator designated it as a build host. These show up as mesh tags, and the node refuses to place an app on a supervisor that lacks the firecracker capability — the match is on capability, not on a per-app runtime choice:

curl -H 'Authorization: Bearer <TABBIFY_TOKEN>' https://api.tabbify.io/v1/supervisors
# [{"display_name":"ec2-prod","tags":["supervisor","docker","builder"]},
#  {"display_name":"thinkpad","tags":["supervisor","firecracker","docker"]}]

In this example, an app would be placed on thinkpad (it advertises firecracker), while ec2-prod serves as a build host. Add more Firecracker- capable supervisors and the node spreads placement across them.

The Firecracker runtime is implemented and proven in production runners, verified live on Linux hosts with real KVM. Wherever an app lands, it gets a stable private mesh address (a deterministic per-app ULA, e.g. fd5a:1f02:…::1) and the runner contract — health, restart, lifecycle — stays the same.