Docker Never Promised
You Isolation. Firecracker Does.
Both get filed under "lightweight virtualization." Both are fast. Only one of them was built to survive running a stranger's code next to yours. Here's the actual boundary, drawn with the numbers AWS itself publishes.
Two tools, solving two different problems
Docker showed up in 2013 to answer one question: how do you package an application and its dependencies so it runs identically on a laptop, a CI runner, and a production node? It succeeded so completely that "container" quietly became a synonym for "how software ships."
Firecracker showed up five years later, out of AWS, to answer a question Docker was never built for: how do you run someone else's code — a Lambda function, a Fargate task — thousands of times a second, on shared hardware, without one tenant ever getting a byte of another tenant's memory?
Both get called "lightweight virtualization." Both are fast enough to feel instant. That's exactly why they get compared — and why the comparison usually misses that they're not actually competing for the same job.
Two stacks, side by side
Follow each one from the hardware up and the difference in kind, not just degree, becomes obvious.
Firecracker
Docker
Docker's process never leaves the host kernel. docker run asks the kernel to hide most of itself from a process group — that's the whole trick, and it's why a container starts as fast as any other process on the box.
Firecracker's guest genuinely boots — a real, independent Linux kernel, talking to real (if minimal) virtual hardware through KVM. It's a virtual machine in the fullest sense. The engineering feat isn't skipping virtualization, like Docker does. It's making virtualization itself disappear into the noise floor.
The trick is the device model
A general-purpose hypervisor like QEMU emulates a PC: BIOS, legacy serial ports, optional GPU passthrough, dozens of device types — because it has to boot arbitrary, unmodified operating systems. All of that is attack surface, and all of it takes time to initialize.
Firecracker, written in Rust and forked from Google's crosvm, throws almost all of it away. It emulates exactly five devices — enough to boot Linux and nothing more:
No BIOS. No legacy device emulation. No GPU. That's why a Firecracker microVM boots in under 125ms instead of a general VM's several seconds — it simply has almost nothing to initialize. AWS wraps each microVM process in a Jailer on top of that — seccomp filters, cgroups, chroot, and its own namespace — so even a hypothetical Firecracker bug still has to get through a second, independent sandboxing layer before it reaches the host.
The spec sheet
Put side by side, the two aren't even optimizing for the same thing.
| Metric | Firecracker | Docker |
|---|---|---|
| Isolation boundary | Hardware, via KVM + own kernel | Kernel, via namespaces/cgroups |
| Boot / start time | < 125ms (full kernel boot) | ~150 – 200ms (process start) |
| Memory overhead | < 5 MiB per microVM | No separate kernel — overhead is per-image |
| Density / creation rate | Thousands per host; 150/sec creation | Hundreds per host, near-instant start |
| Own kernel? | Yes — independent guest kernel | No — inherits the host's |
| Built by / language | AWS, Rust (from crosvm) | Docker Inc., primarily Go |
Firecracker's numbers read like a container's. Its isolation model reads like a VM's. That combination — not raw speed alone — is the actual invention. Docker was never trying to solve the same equation; density and packaging speed were the whole point, and a shared kernel was an acceptable, even desirable, price for first-party workloads.
The twist: they're usually nested, not rivals
Here's the detail that resolves "Firecracker vs. Docker" as a bit of a trick question: AWS built firecracker-containerd, a shim that lets containerd — the same runtime Docker itself is built on — manage containers as Firecracker microVMs instead of as shared-kernel processes.
Which means every one of Lambda's 15 trillion-plus monthly invocations, and every Fargate task, follows the same pattern: boot a Firecracker microVM with its own tiny kernel, then run the customer's ordinary OCI container — the exact same image format Docker produces — inside it, through the exact same containerd tooling. Kata Containers does the equivalent for Kubernetes pods that need the same treatment.
Docker's packaging format didn't lose to Firecracker. It got a harder floor put underneath it, one tenant at a time.
Choosing the boundary you actually need
Your own services, a single trust domain, a kernel version you control. The default for internal microservices, CI steps, and most of what sits behind a Kubernetes Service — no hostile neighbor to defend against.
You're running code you don't fully trust, per-invocation, at high density — serverless functions, third-party plugins, CI on external pull requests. Use Lambda, Fargate, or another Firecracker-based platform (Fly.io, Koyeb) rather than reaching for the VMM directly.
You want the same VM-grade wall as Firecracker but need it to look and behave like an ordinary pod to Kubernetes — the middle path when you're not on a Firecracker-native platform already.
Docker was never dishonest about what it offered — it just never claimed to guard against a hostile neighbor, because that was never the job. Firecracker exists because someone eventually had to actually do that job, at a scale where a real hypervisor's overhead would have been unaffordable. The two didn't end up rivals. One became the floor the other now quietly runs on, fifteen trillion times a month, without either of them getting the credit in the same sentence.