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
# 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
depends_on with service_healthy + service_completed_successfully.--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.pivot_root for builds./clone spawns a new VM with a fresh tap and re-IP'd guest. Live migration (stop-and-copy).gocracker-sandboxd — warm pools, content-addressed templates, HMAC-signed preview URLs. Python · Go · JS SDKs.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.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.Ctrl+Shift+G. Sidebar lists live sandboxes. TypeScript runs via Bun natively — no transpile step.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
# 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
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
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()
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.