all posts

Firecracker vs AWS Lambda: Same Engine, Different Boundary

Ajay Kumar··9 min read

"Firecracker vs AWS Lambda" is a strange matchup to search for, because they're on the same team. AWS wrote Firecracker specifically to run Lambda — the open-source virtual machine monitor was born inside Lambda's isolation problem and later given away under Apache-2.0. So this isn't a primitive versus a rival. It's a primitive versus a managed product built on that exact primitive. Every Lambda invocation you've ever run executed inside a Firecracker microVM. The interesting question, then, isn't "which isolates better" — the isolation engine is literally the same — it's "what do you get from owning the VMM yourself versus renting AWS's opinionated wrapper around it?"

The shared foundation: both are microVMs

Start with what's identical, because it's the whole reason the comparison is interesting. A Lambda function does not run in a container in the way people casually assume. AWS built Firecracker precisely because containers weren't a strong enough boundary for running thousands of tenants' untrusted code on shared fleets. So each Lambda execution environment is a Firecracker microVM: a real guest kernel, hardware-enforced memory isolation via KVM, and a stripped-down device model — no BIOS, no PCI bus, just a handful of virtio devices. If you run Firecracker yourself, or a platform like PandaStack on top of it, you get the same boundary. The wall is identical. What differs is everything around the wall.

The isolation boundary is not the differentiator. Lambda and a self-hosted Firecracker fleet both give each execution its own guest kernel behind a KVM wall. AWS just wrote the VMM and open-sourced it, then kept building the managed layer on top.

What Lambda gives you (and what you inherit with it)

Lambda's pitch is that you never see the microVM. You upload a handler, and AWS runs the entire lifecycle: placement, scaling, the fleet, patching, the works. That's genuinely valuable — for a lot of workloads, not thinking about any of this is the correct engineering decision. But a fully-managed product means you also inherit its opinions, and Lambda has firm ones. (Treat the specifics below as directional and verify against current AWS docs — limits and behaviors change.)

  • A hard maximum execution time — Lambda's ceiling is 15 minutes per invocation. Anything longer isn't a tuning problem, it's the wrong tool.
  • Cold starts you can influence but not fully own — you can pay for provisioned concurrency to keep environments warm, but the underlying create/reuse policy is AWS's to decide, not yours.
  • Execution-environment reuse — your handler often runs in a warm environment that already served a prior invocation from you. Great for latency, but it means process-global state can leak between your own invocations, and you don't control when a fresh one spins up.
  • No persistent local state — the local filesystem is scratch (/tmp) and disappears; durable state has to live in something else (S3, a database, EFS).
  • Constrained networking — you get VPC attachment and AWS's networking model, not byte-level control of egress, custom routing, or arbitrary kernel-level network config.
  • AWS-shaped, AWS-hosted — it runs in AWS regions, on AWS's schedule, with AWS's pricing model. On-prem or another cloud isn't on the menu.

None of these are flaws. They're the price of "you never think about the microVM." For a webhook handler, a thumbnail resizer, or a glue function between two AWS services, that price is a bargain.

What raw Firecracker gives you

Running Firecracker yourself flips the trade. Now you own the fleet, which means you own every decision Lambda made for you. The kernel is yours — you can ship a custom guest kernel, tune it, enable or strip features. The networking is yours down to the byte: you decide the egress policy, the routing, whether a sandbox can reach the internet at all. The lifecycle is yours — you decide when a VM is created, reused, snapshotted, forked, or destroyed, and there's no invisible reuse policy leaking state between runs unless you build one. And critically, you get the two Firecracker superpowers Lambda simply does not expose: snapshot and fork.

Snapshot lets you freeze a fully-booted, running microVM — its entire RAM plus device and vCPU state — to disk, and restore it later mid-instruction. Restore isn't boot; the guest wakes up exactly where it froze, page cache warm, processes already running. Fork clones a running VM via copy-on-write, so a parent VM's memory and disk are shared with a child until one of them writes. These are the primitives behind sub-second create and branch-of-thought agent patterns, and they're inaccessible from behind Lambda's managed wall. You can't ask Lambda for a memory snapshot of your running function, and you can't fork it.

Lambda hides the microVM so well that you lose the microVM's best tricks. Snapshot and fork are Firecracker features you can only reach if you're the one holding the VMM.

Where they actually diverge

Line them up on the things that aren't the isolation wall, because that's where the real decision lives:

  • Control — Lambda: AWS owns the fleet, kernel, networking, and lifecycle. Firecracker: you own all of it, for better and for the operational weight that comes with it.
  • Execution reuse — Lambda: warm environments may serve prior invocations; state can bleed between your own calls. Self-hosted: you decide reuse policy — fresh VM per request is a config choice, not a fight with the platform.
  • Snapshot & fork access — Lambda: not exposed. Firecracker: first-class — freeze/restore a running VM, CoW-fork it, build fork trees.
  • Max runtime — Lambda: 15-minute hard ceiling per invocation (verify against AWS docs). Firecracker: however long you want; the VM lives until you kill it.
  • Persistent local state — Lambda: scratch /tmp only. Firecracker: attach durable volumes; keep a VM alive as long as you like.
  • Networking control — Lambda: AWS's VPC/networking model. Firecracker: byte-level — your own netns, routing, and egress rules per VM.
  • Where it runs — Lambda: AWS regions only. Firecracker: any KVM host — another cloud, bare metal, or on-prem.
  • Cost model — Lambda: per-invocation + duration billing, near-zero idle, but a per-request floor and provisioned-concurrency surcharge to kill cold starts. Firecracker: you pay for the hosts, and density/economics are yours to tune.

When running your own Firecracker wins

The honest default is: if Lambda's constraints fit, use Lambda. Not paying for the fleet, the patching, and the on-call is a real feature, and "we run our own microVM fleet" is a sentence that should come with a good reason. Here's when that reason exists:

  • You're running genuinely untrusted, multi-tenant code and want direct control of the isolation and egress boundary — AI-agent-generated commands, per-user code playgrounds, arbitrary customer repos — rather than trusting a managed reuse policy you can't inspect.
  • You need snapshot or fork — branch-of-thought agents, instant clones of a warmed-up environment, or restoring a frozen session. Lambda can't give you the primitive.
  • You want a fresh, isolated VM per request that you control end-to-end, with no cross-invocation state reuse and no 15-minute ceiling.
  • You're not on AWS, or can't be — on-prem, air-gapped, sovereignty requirements, or another cloud entirely.
  • The economics of a warm-pool-free, snapshot-restore fleet at your scale beat per-invocation billing, and you'd rather own the density.

This is the exact line PandaStack is built on. It's an open-source Firecracker platform — the same Apache-2.0 VMM that backs Lambda — that hands you the primitive instead of hiding it. Every sandbox is its own microVM, created via snapshot-restore at a p50 of 179ms and a p99 around 203ms (the restore-and-resume step itself is roughly 49ms of that). The genuine cold boot happens once per template at around 3 seconds and is then baked into a snapshot and amortized away. You get the snapshot and fork primitives directly — same-host forks land in 400–750ms, cross-host in 1.2–3.5s — plus byte-level networking (each agent pre-allocates 16,384 /30 subnets for per-VM network namespaces) and self-hosting on any KVM host. It's Lambda's engine without Lambda's wall.

A per-request VM you actually control

The clearest way to see the difference is the create-run-teardown loop that Lambda hides from you. Here it is fresh VM per request, no warm-environment reuse, using the Python SDK:

from pandastack import Sandbox

# One fresh, isolated microVM per request — restored from a baked snapshot
# (~179ms p50), NOT cold-booted, and NOT reused from a prior invocation.
# Unlike a Lambda warm environment, nothing from the last request survives.
def handle(request: dict) -> dict:
    with Sandbox.create(template="code-interpreter", ttl_seconds=120) as sbx:
        # Run untrusted / model-written code inside its own guest kernel.
        sbx.filesystem.write("/workspace/task.py", request["code"])
        result = sbx.exec("python3 /workspace/task.py", timeout_seconds=30)
        return {
            "exit_code": result.exit_code,
            "stdout": result.stdout,
            "stderr": result.stderr,
        }
    # VM destroyed on block exit. No /tmp to leak, no execution environment
    # left warm for the next caller to inherit. That's the point.

# print(handle({"code": "print('hello from a microVM you own')"}))

Two things that snippet gives you that a Lambda handler can't. First, `ttl_seconds` and `timeout_seconds` are your caps, not a platform-imposed 15-minute ceiling — set them to match your workload, up or down. Second, and more importantly, the isolation is per-request by construction. There is no previous tenant in that VM because you created it for this request and destroyed it after. On Lambda, your handler might be running in an environment that served your last call, and you have to code defensively around that. Here, the fresh wall is the default.

The real takeaway

"Firecracker vs AWS Lambda" resolves to a question about ownership, not isolation. The isolation is the same microVM — AWS made sure of that when they wrote Firecracker. Lambda wraps that microVM in a managed product and, in exchange for never making you think about it, keeps the snapshot, the fork, the kernel, the networking, and the lifecycle for itself. Run Firecracker yourself and you take all of that back, along with the operational weight of a fleet. Most of the time, Lambda's trade is the right one. But when you need untrusted-multi-tenant control, snapshot/fork, a per-request VM with no reuse, or a home that isn't AWS — you don't need a different isolation engine. You just need the one AWS already open-sourced, with the wall taken down.

Frequently asked questions

Is AWS Lambda built on Firecracker?

Yes. AWS wrote Firecracker specifically to run Lambda, and open-sourced it under Apache-2.0 in 2018. Each Lambda execution environment is a Firecracker microVM with its own guest kernel and hardware-enforced isolation via KVM — not a plain container. Fargate uses Firecracker too. So Firecracker and Lambda aren't competitors: Lambda is a managed product built on the Firecracker VMM.

If Lambda uses Firecracker, why run Firecracker myself?

Because Lambda hides the microVM and, with it, the microVM's best capabilities. Running Firecracker yourself gives you snapshot and fork (freeze/restore a running VM, copy-on-write clone it), a custom guest kernel, byte-level networking and egress control, no 15-minute runtime ceiling, control over execution reuse so nothing leaks between requests, and the ability to run on any KVM host including on-prem. Lambda trades all of that away in exchange for being fully managed — a good deal for many workloads, but not when you need those primitives.

Does Lambda reuse execution environments between invocations?

Yes — for latency, your handler often runs in a warm execution environment that already served a prior invocation of your function. That means process-global state can persist (and leak) between your own calls, and you don't control when a fresh environment is created. If you need guaranteed per-request isolation with no reuse, you either code defensively around it or run a fresh microVM per request on infrastructure you control. Verify current reuse behavior against AWS docs, as it evolves.

What is Lambda's maximum execution time versus a self-hosted microVM?

Lambda enforces a hard maximum of 15 minutes per invocation (verify against current AWS docs). A self-hosted Firecracker microVM has no such ceiling — the VM lives until you tear it down, so long-running jobs, persistent sessions, and stateful workloads that don't fit Lambda's window run fine. On PandaStack you set the lifetime yourself via a TTL, and a persistent flag exempts a VM from idle reaping entirely.

Is a self-hosted Firecracker sandbox as fast to start as Lambda?

Both rely on the same trick: snapshot a fully-booted microVM and restore it instead of cold-booting. On PandaStack, a fresh isolated microVM is created at a p50 of 179ms and p99 around 203ms via snapshot-restore, with the genuine cold boot (~3s) paid once per template and then amortized away. That's competitive with a warm Lambda environment, without needing a warm pool — every create takes the restore path.

Run code in a microVM in one API call.

49ms p50 cold start. Fork, snapshot, and scale to zero.

Start free
Written by Ajay Kumar, Founder, PandaStack.