A micro-VMM in pure Go that does everything Firecracker does at the KVM level — virtio devices, jailer, seccomp — and adds the developer experience on top. Pull any OCI image, build any Dockerfile, clone any git repo, orchestrate Compose stacks. Each service becomes a real Linux VM.

$ sudo ./gocracker run --image alpine:latest --kernel ./vmlinux --wait
[oci] cache hit alpine:latest (linux/amd64)
[container:INFO] started id=gc-26655 duration=284ms
[vmm:INFO] vm running id=gc-26655 vcpus=1 mem_mb=128

── install ───────────────────────────────────────────

# linux/amd64 — arm64 also published, just swap the arch
curl -L https://github.com/misaelzapata/gocracker/releases/download/v0.2.0/gocracker-v0.2.0-linux-amd64.tar.gz | tar xz
cd gocracker-v0.2.0-linux-amd64

# grab a guest kernel (or build your own with `make kernel-guest`)
curl -L -o vmlinux.gz https://github.com/misaelzapata/gocracker/raw/main/artifacts/kernels/gocracker-guest-standard-vmlinux.gz
gunzip vmlinux.gz

# one-time kvm group setup (then no more sudo)
sudo usermod -aG kvm $USER && newgrp kvm

# boot rootless (slirp network, no TAP/iptables required)
./gocracker run --image alpine:latest --kernel ./vmlinux \
                --net slirp --cmd "echo hello from a real VM" --wait

no docker daemon · no containerd · no runc · just kvm


── features ──────────────────────────────────────────

container sources
OCI registries, local Dockerfiles (BuildKit AST), git repos with auto-detected Dockerfiles, plain directories.
compose orchestration
Docker Compose stacks as microVMs. In-guest healthchecks. depends_on with service_healthy + service_completed_successfully.
networking
--net slirp runs fully rootless — userspace network stack, no TAP, no iptables, no sudo after the one-time kvm group setup. --net auto creates TAP + IPv4 + NAT for higher-throughput workloads. Per-stack namespaces, deterministic MACs, port publishing.
kvm isolation
Hardware virt + Firecracker-style jailer + per-arch seccomp + private mount namespaces + pivot_root for builds.
snapshot · restore · clone
Full RAM + vCPU + device snapshot. In-place /clone spawns a new VM with a fresh tap and re-IP'd guest. Live migration (stop-and-copy).
sandbox control plane
gocracker-sandboxd — warm pools, content-addressed templates, HMAC-signed preview URLs. Python · Go · JS SDKs.
cassette deploys
Application code lives on a separate ext4 disk — not baked into the rootfs. The base VM (runtime + deps) is a frozen snapshot. Swap the cassette to deploy a new version. The VM never reboots. Multiple cassettes in one running VM for instant version comparison. → full explanation
warm runtime
base-node-warm template pre-loads V8 inside the snapshot. Node.js code eval goes from ~50 ms cold to ~5–10 ms warm, no reboot.
MCP server
gocracker-mcp exposes a Model Context Protocol server so AI coding agents (Claude, Copilot, Cursor) can spin up sandboxes, run code, and read output without leaving the chat.
VS Code extension
Run selected code or an entire file in a real KVM micro-VM with Ctrl+Shift+G. Sidebar lists live sandboxes. TypeScript runs via Bun natively — no transpile step.

── cassette deploys ─────────────────────────────────

Every platform today bakes code and runtime into the same container image. gocracker separates them — permanently.

# everyone else:
git push → docker build  (rebuild runtime + code)
         → image push    (upload gigabytes)
         → image pull    (on every node)
         → container restart  (cold boot)

# gocracker cassette:
git push → pack code into ext4  (seconds, code only)
         → attach cassette     (warm VM, no reboot)live in < 100 ms

The base VM — kernel, runtime, all dependencies — is a frozen snapshot built once. It never changes across deploys. Only the cassette (an ext4 disk carrying your application code) is swapped. This is the same separation Vercel achieves with bundles and V8 isolates, but with real KVM hardware isolation per tenant.

console (VM snapshot, frozen)    cassette (ext4, swappable)
┌──────────────────────────┐     ┌──────────────────────────┐
│ node:20-alpine           │     │ app-v42.ext4             │
│ + Express + all deps     │ ←── │ ├── index.js             │
│ + runtime config         │     │ ├── routes/              │
│ restored in ~40 ms       │     │ └── package.json         │
└──────────────────────────┘     └──────────────────────────┘
                                   ↑ swap this, not the console
instant rollback
Point to the previous cassette. No image rebuild, no container restart. The VM is already running.
preview environments for free
Each pull request gets its own ext4. They all share the same base VM snapshot — no extra memory for the runtime.
A/B deploys
Two VMs, same snapshot, two different cassettes. Route traffic split between them. Swap one cassette to promote the winner.
AI code execution
AI agents (Claude, Copilot, GPT) that execute code don't need to rebuild a container per session. One cassette per conversation — the runtime VM is always warm. Swap in the user's code, run it, tear down the cassette. No Docker, no heavy orchestration.
multiple versions, one VM
Attach several cassettes simultaneously. Exec into any version without rebooting — useful for migration testing and benchmarking across versions.
# two versions, one running VM
sandboxd run --image node:20-alpine \
  --code-disk ./app-v41.ext4:/data/v41 \
  --code-disk ./app-v42.ext4:/data/v42

toolbox exec node /data/v41/app.js   # → v41 output
toolbox exec node /data/v42/app.js   # → v42 output — same VM, no reboot

To our knowledge, no other open-source microVM project exposes cassette-style deploys as a first-class API. · examples


── numbers ───────────────────────────────────────────

Ryzen AI 9 HX 370 · Linux 6.17 · /dev/kvm. Reproduce: sandboxes/examples

cold boot       alpine, warm OCI cache           ~ 80 ms
warm restore    snapshot, in-place               ~ 40 ms
lease p95       warm pool, sandboxd              ~ 1.5 ms
node eval warm  base-node-warm, V8 preloaded     ~ 5–10 ms
template hit    content-addressed cache          ~ 80 µs
regression      real-world projects in the gate    378
arch parity     x86-64 + ARM64 (Graviton 1)        full

── sdk ───────────────────────────────────────────────

Most users skip raw HTTP. Typed errors, context-manager lifecycle, pipelined CONNECT.

from gocracker import Client

client = Client("http://127.0.0.1:9091")

# cassette deploy — swap the ext4, not the VM
sb = client.create_sandbox(
    image="node:20-alpine",
    network_mode="none",
    code_disks=[
        {"host_path": "/disks/app-v1.ext4", "mount": "/data/v1", "read_only": True},
        {"host_path": "/disks/app-v2.ext4", "mount": "/data/v2", "read_only": True},
    ],
)
tb = sb.toolbox()
r1 = tb.exec(["node", "/data/v1/app.js"])  # v1
r2 = tb.exec(["node", "/data/v2/app.js"])  # v2 — same VM, no reboot
sb.stop()

python · go · js / node


── why ───────────────────────────────────────────────

I fell in love with Firecracker — booting a real Linux VM in milliseconds with minimal overhead is brilliant. But every time I wanted to just run a container image as a microVM, I had to pull the image manually, extract the rootfs, build an ext4 disk, generate an initrd, write a JSON config, set up a TAP interface, configure iptables… and only then call the Firecracker API. I kept thinking: why can't I just type one command?

So I built gocracker. Hobby project that grew into something that boots 378 real-world projects, runs Flask + PostgreSQL compose stacks on ARM64 bare metal, and ships a Firecracker-compatible REST API. All in a single static binary.