all posts

Cloudflare Sandbox SDK vs E2B for Agent Code

Ajay Kumar··10 min read

Somewhere in your codebase there is a string that a language model produced, and in a minute you are going to hand it to an interpreter and press go. That is the entire job. Every product in this category is just an answer to the follow-up question: whose kernel does it land on, and what happens to the machine afterwards. Two answers keep landing on the same shortlist right now — Cloudflare's Sandbox SDK (the code-execution layer that sits on top of Cloudflare Containers, reachable from Workers and orchestrated through Durable Objects) and E2B (a standalone sandbox API with Python and TypeScript SDKs built around a code-interpreter workflow).

On a feature grid they rhyme: create a sandbox, write a file, run a command, read stdout, tear it down. Underneath they are two different architectural bets, and the bet is the decision. One says your execution environment should live inside the same edge platform your app already runs on, addressed through that platform's programming model. The other says execution should be a portable dependency that knows nothing about where your app lives. Those pull your architecture in opposite directions, and six months from now that is the difference you will actually feel.

I'm Ajay. I built PandaStack, which is also in this category, so read accordingly. My rule for these posts: specific and numeric about my own platform, qualitative about everyone else's, because I will not publish a benchmark of a product I do not operate. There is one clearly-labelled PandaStack section near the end that you are free to skip, and a verdict section that recommends both of the headline products over mine under conditions that are extremely common.

Both products ship fast. As of writing, runtime limits, session semantics, container behaviour and pricing were all still moving. Treat every characterisation here — including mine — as a prompt to go read the current docs, not a replacement for reading them. Verify against their current documentation before you architect around any of this.

Two different bets, not two brands of the same thing

Cloudflare's bet is that compute should be an extension of the network you are already behind. The Sandbox SDK is designed to be reached from a Worker; the sandbox's identity and lifecycle are tied to a Durable Object, which is Cloudflare's answer to "where does per-entity state live." That is an elegant fit for a certain shape of application: a request arrives at the edge, a Worker decides it needs to execute something, and the execution environment is addressable by the same ID scheme the rest of your app already uses. You do not stand up a second control plane, you do not add a second auth story, and the thing running your code is inside the same platform that already terminates TLS for you.

E2B's bet is the opposite one: that execution should be a boring, portable HTTP dependency. It is a standalone sandbox API with first-class Python and TypeScript SDKs, shaped by the code-interpreter workflow — the model writes Python, you run it, you read the traceback, you try again. It makes no claim on where your app lives. Your backend can be on AWS, Fly, a Hetzner box or your laptop, and E2B is one more client in your dependency list. That is a smaller architectural commitment, and it costs you a second vendor and a second bill.

One is compute shaped like a feature of the platform your app lives on. The other is compute shaped like a library. Neither is an insult; they just make different things easy and different things permanent.

Everything below follows from that. Platform-native compute is fast to adopt and slow to leave. Provider-neutral compute is one more thing to operate and one fewer assumption welded into your code.

Isolation: what boundary are you actually getting?

This is where vendors are most tempted toward adjectives and readers are most tempted to accept a blog post as evidence, so let me be careful. As of writing, Cloudflare's sandbox story runs on their container platform, which is a materially different isolation model from Workers' V8 isolates — a Worker is a language-runtime sandbox, whereas a container gives you a real filesystem, real processes and arbitrary binaries. E2B publicly describes microVM-based isolation for its sandboxes. Both of those are reasonable categories of answer. What neither I nor any comparison post can tell you is the current, specific boundary each one commits to in writing today. Go and read it.

The three questions worth asking each vendor, in writing, are always the same. What is the boundary — a namespace, a hardened runtime, a hypervisor? Who else is inside it with my workload? And what is the blast radius when a kernel CVE drops on a Friday afternoon? If the boundary is a shared kernel, one kernel bug is a shared-fate event across every tenant on that host. If the boundary is hardware virtualization, the guest gets its own kernel, and the surface an attacker has to break shrinks from the whole Linux syscall interface down to a small virtio device model. It does not make you invulnerable — every VMM has its own CVE history — but the thing that has to break is orders of magnitude smaller.

Why it deserves ten minutes rather than a checkbox: model-generated code is untrusted code in the formal sense. Not "probably fine" — the input that produced it came from outside your trust boundary, and the thing that wrote it cannot be reasoned about. An LLM that confidently runs a recursive delete is not a hypothetical failure mode, it is a Tuesday. The only question that matters is whose kernel it lands on and whether that kernel is holding anyone else's data.

Lifecycle, cold start, and where the state goes

The single most consequential difference is the mental model for how long a sandbox lives and what survives between calls, and it falls straight out of the architectural bet.

Cloudflare's model is entity-shaped. Because lifecycle is tied to a Durable Object, you get an addressable, long-lived-ish identity that requests route back to — which is genuinely a nice fit for "this user's session" or "this agent's workspace." But that identity lives inside a platform with its own rules about hibernation, eviction and how long a thing may run, and those rules are the platform's to change. As of writing I would not repeat any specific ceiling to you, because I would be quoting a number that may already be stale. Check it yourself, and check it for the exact tier you will be on.

E2B's model is session-shaped. You create a sandbox for a piece of work, it stays alive while the agent iterates, and you kill it when the turn is done. That maps cleanly onto an agent loop that needs to run code, look at the result, install something it forgot, and run it again — the filesystem and the installed packages are still there on the second call, which is the whole point. Confirm the current maximum lifetime and how (or whether) you extend it, because that number moves and it is exactly the number that decides whether your 40-minute job is a design or a rewrite.

Two axes decide this more often than the rest combined: how long a sandbox may live, and whether outbound network access can be constrained. Everything else you can work around in application code. Those two you design around — so get them from the docs, in writing, before you write the loop.

On cold start, resist the urge to compare marketing numbers. The honest framing is that these systems pay their startup cost in different currencies: an edge platform amortises it by keeping things near the request and reusing warm instances; a sandbox API amortises it with pre-built templates so your environment is not installed from scratch on every run. The number you care about is not either vendor's best case — it is the p99 of your own workload, from your own region, with your own two ugliest dependencies installed. Measure it. It takes an afternoon and it beats every comparison table, including the one directly below.

Side by side on the axes that bite

PandaStack is in every line so you can see where it sits rather than infer it. Everything about the other two is deliberately qualitative — verify against their current docs.

  • Programming model — Cloudflare Sandbox SDK: bound to Workers and Durable Objects; you reach the sandbox from a Worker and its lifecycle hangs off a DO, which is elegant if your app is already Workers-native and awkward if it is not. E2B: a plain API with Python and TypeScript SDKs, callable from any backend, no host-platform assumptions. PandaStack: REST API plus Python and TypeScript SDKs, same deal — no assumption about where your app runs, and Apache-2.0 if you would rather run the whole thing yourself.
  • Isolation boundary — Cloudflare Sandbox SDK: runs on their container platform, a different and stronger model than Workers isolates; confirm the specific tenancy guarantees with them rather than with me. E2B: publicly describes microVM-based isolation; verify the current details. PandaStack: one Firecracker microVM per sandbox, its own guest kernel, its own network namespace, drawn from 16,384 pre-allocated /30 subnets per agent host.
  • Lifecycle shape — Cloudflare Sandbox SDK: entity-shaped, tied to a Durable Object's lifecycle and the platform's hibernation and duration rules. E2B: session-shaped, created for a unit of agent work and killed when the turn ends. PandaStack: lives until ttl_seconds expires, you kill it, or the idle reaper takes it; sandboxes flagged persistent are exempt from the reaper entirely.
  • State between calls — Cloudflare Sandbox SDK: durable state is the Durable Object's job; treat what is on the container's disk as belonging to that instance's lifetime and read their current persistence semantics carefully. E2B: the sandbox filesystem persists for the session's life, which is what makes the install-then-iterate loop work; confirm what survives beyond the session on your tier. PandaStack: the rootfs is a copy-on-write clone that persists for the sandbox's life, snapshots capture both disk and memory, and durable volumes exist for state that must outlive the VM.
  • Filesystem and pip install ergonomics — Cloudflare Sandbox SDK: real container filesystem, so a package manager works; the open question is where install time lands in your request path and how you bake a base image. E2B: an explicit template system so you bake the environment once and start from it, plus filesystem and process APIs designed for exactly this. PandaStack: a full Ubuntu 24.04 guest with mise-managed Node, Python, Go and Bun pre-warmed, so apt/pip/npm is a normal problem, and templates are baked into snapshots rather than installed at boot.
  • Network egress control — Cloudflare Sandbox SDK: you are inside a network company's network, which cuts both ways; ask specifically what egress policy you can express for sandbox traffic. E2B: check their current controls against your threat model before assuming you can pin a sandbox to one endpoint. PandaStack: each sandbox has its own netns, veth pair and NAT rules, which is the layer where allow-list egress is actually enforceable rather than aspirational.
  • Fit for an agent loop — Cloudflare Sandbox SDK: excellent when the loop is triggered by a request already hitting your Worker and the agent's identity maps to a DO. E2B: purpose-built for it; run code, read the traceback, patch, rerun, with the environment intact between steps. PandaStack: same loop, plus fork — branch a running sandbox to explore several fixes in parallel, 400-750ms same-host, 1.2-3.5s cross-host.
  • Portability and lock-in — Cloudflare Sandbox SDK: the execution primitives port fine, but the surrounding assumption (your app is Workers-native, your state is in Durable Objects) does not; leaving is a platform decision, not a library swap. E2B: high — it is already a standalone dependency. PandaStack: high, and self-hosting is the escape hatch of last resort.
  • Pricing model shape — Cloudflare Sandbox SDK: priced like platform compute, folded into the same bill and the same account as the rest of your edge usage, which is either delightful consolidation or an unattributable line item depending on your finance team. E2B: priced like a sandbox vendor — you can see what execution costs as its own number. PandaStack: usage-based on the resources a sandbox actually holds, one rate card across classes, no per-request charge. Compare shapes, not the numbers in anyone's blog post, including this one.

The loop both products exist to serve

Strip the branding off and every product here is serving the same dozen lines: ask the model for code, put it somewhere that is not your API process, run it, feed the failure back, repeat until it works or you run out of patience. Here is the shape, in pseudocode, deliberately not claiming to be either vendor's real API.

// ILLUSTRATIVE PSEUDOCODE — this is the SHAPE of the loop, not the real
// method names of any vendor. Do not copy-paste this expecting it to run;
// read the current SDK docs for whichever product you pick.

async function agentTurn(question: string) {
  const box = await sandboxProvider.create({ image: "python" });
  const failures: string[] = [];

  try {
    for (let attempt = 0; attempt < 5; attempt++) {
      // Freshly generated, unreviewed, extremely confident about pandas.
      const source = await askModelForPython(question, failures);

      await box.writeFile("/work/step.py", source);
      const run = await box.run("python /work/step.py");

      if (run.exitCode === 0) return run.stdout;
      failures.push(run.stderr.slice(0, 4000));
    }
    throw new Error("no working code in 5 attempts");
  } finally {
    await box.destroy(); // the unglamorous line that keeps the invoice unglamorous
  }
}

Notice what that loop is doing: taking a string a statistical model produced from a prompt a stranger typed, writing it to disk, and asking a computer to execute it. Five times. With a retry. We have collectively decided this is a normal thing to ship, and it is — but only because the execution happens somewhere disposable. Run the same loop in your API process and you have built a remote code execution vulnerability with a roadmap and a pricing page.

The architectural question is where that box comes from. On the Cloudflare side, it comes from inside the request path you already own. On the E2B side, it comes from a vendor your backend calls out to. Both are defensible. Only one of them is still true if you move your app off the edge next year.

The third option (yes, this is the PandaStack bit)

Clearly labelled so you can skip it. PandaStack is a third bet: standalone API and SDKs like E2B, but with the isolation boundary and the fork primitive as the design center. Every sandbox is its own Firecracker microVM with its own guest kernel and its own network namespace. The usual objection to VMs is that they are slow to start — that is a boot-path problem, not a virtualization problem. Every create restores a pre-baked snapshot rather than cold-booting: the restore step itself is about 49ms, inside a p50 of 179ms end to end and a p99 around 203ms, with no warm pool of idle VMs. The only roughly 3-second boot is the very first spawn of a template, before its snapshot exists.

The primitive neither of the other two offers in the same form is fork: branch a running sandbox, memory and all, with copy-on-write memory and a reflinked rootfs — 400-750ms on the same host, 1.2-3.5s cross-host. That turns "the model proposed three fixes" into three live machines that each start from the exact state where the failure happened, instead of three cold sandboxes that re-install the same three gigabytes of wheels. Sandboxes are also long-lived and stateful by default: they run until their TTL, or forever if you mark them persistent.

from pandastack import Sandbox

# ttl_seconds is the backstop for the day your process dies mid-loop and
# never reaches the cleanup path. Always set it. Ask me how I know.
with Sandbox.create(template="code-interpreter", ttl_seconds=900) as sbx:
    # The model wrote this. Nobody has read it. That is the entire point
    # of it running over there instead of in your API process.
    sbx.filesystem.write("/work/analysis.py", model_output)

    setup = sbx.exec("pip install pandas pyarrow", timeout_seconds=300)
    if setup.exit_code != 0:
        raise RuntimeError(setup.stderr)

    run = sbx.exec("python /work/analysis.py", timeout_seconds=600)
    print(run.exit_code, run.stdout[:2000], run.stderr[:2000])

    report = sbx.filesystem.read("/work/report.csv")  # bytes
    print(report.decode("utf-8")[:500])

# The context manager kills the sandbox. If you are not using it,
# call sbx.kill() in a finally block and mean it.

Now the honest trade-off, because a comparison post that only lists advantages is an advert. You run against our API and our region model, not an edge network that is already sitting in front of your users. If your app is Workers-native and your traffic already terminates at Cloudflare, calling us means an outbound hop from your platform to ours, plus a second vendor, a second key to rotate and a second status page to care about. Cloudflare's proximity to your request path is a real and unmatched advantage in that scenario, and no amount of restore-latency bragging on my side changes it. Pick us for the boundary, the fork primitive and long-lived stateful sandboxes; do not pick us hoping to get edge adjacency, because we do not sell that.

Which should you actually pick

In rough order of how often I see each case. The first two are recommendations for the other guys.

  1. Your app is already Workers-native — pick Cloudflare. If your requests terminate at Cloudflare, your state already lives in Durable Objects and your team lives in that dashboard, adding a second execution vendor buys you a second on-call rotation and very little else. Integration gravity is a genuine engineering asset when it pulls in the direction you were already walking. Confirm the current runtime limits fit your longest realistic job before you commit.
  2. Your problem is literally "the model wrote Python, now what" and your backend is anywhere else — pick E2B. It is purpose-built for the code-interpreter loop, the SDKs read like they were written by people who have shipped an agent, and the template system means your environment is defined once rather than installed on every run. If your constraint is developer-time rather than isolation posture, that maturity is worth paying for.
  3. The isolation boundary is a compliance artifact rather than a preference — get it in writing from whoever you pick. If you run strangers' code for regulated customers, you need a documented boundary, per-tenant network isolation and controllable egress, from a vendor willing to put it in a document rather than a launch blog. Ask all three of us the Friday-CVE question and compare the answers, not the adjectives.
  4. You need long-running or genuinely stateful sessions — check the ceilings first, on every candidate. A 30-minute build, a multi-hour job, or a session that must survive across many user turns is where request-shaped compute tends to run out of road. This is the number that most often forces a migration nine months in.
  5. You want to branch execution state, not just re-run it — that narrows the field fast. Best-of-N exploration, speculative fixes and "resume from the exact moment it broke" all want a fork primitive with copy-on-write memory rather than a fresh sandbox and a replayed setup script. That is the thing PandaStack was built around.
  6. You need to self-host or run in your own cloud account — ask early, not at the security review. Data residency, air-gapped environments and "our team will not approve outbound sandbox traffic" are real constraints that eliminate options quietly. PandaStack is Apache-2.0 and the same agent binary runs on your own KVM hosts; verify each other vendor's current story directly with them.

How to decide in a day

Do not build a matrix. Build the smallest thing that would embarrass you in production and run it on each candidate: create a sandbox, install your two ugliest dependencies, run your longest realistic job, try to reach an endpoint you are supposed to be blocked from, kill everything, then check whether anything survived that should not have. Time every step from the region you will actually deploy to. Then read the two pages nobody reads — limits and security — and ask each vendor the single question your architecture depends on.

And write the forty-line wrapper on day one: create, exec, writeFile, destroy, with a rule that nothing else in your codebase imports a vendor SDK directly. It costs an hour and it converts a future migration from a project into a pull request. Given how fast all three of these products are moving, that hour is the highest-confidence recommendation in this entire post — which is also your reminder to verify every characterisation above against each vendor's current documentation before you architect around it.

Frequently asked questions

What is the real difference between Cloudflare's Sandbox SDK and E2B?

It is an architectural bet, not a feature gap. Cloudflare's sandbox layer is designed to be reached from a Worker, with lifecycle and identity tied to a Durable Object, so execution lives inside the edge platform your app already runs on and inherits that platform's programming model, auth context and runtime rules. E2B is a standalone sandbox API with Python and TypeScript SDKs, built around the code-interpreter workflow, and it assumes nothing about where your backend is hosted. Pick Cloudflare for integration gravity if you are already Workers-native; pick E2B if you want portable execution you can call from any stack. Both ship fast, so verify the current specifics against their own documentation before you design around them.

Which one is safer for running untrusted AI-generated code?

As of writing, Cloudflare's sandbox story runs on their container platform — a materially stronger model than Workers' V8 isolates, since you get a real filesystem and real processes — and E2B publicly describes microVM-based isolation. Both are reasonable categories of answer, and neither should be settled by a blog post. Ask each vendor three things in writing: what exactly is the boundary, who else shares it with your workload, and what the blast radius is when a kernel CVE lands. If the boundary is a shared kernel, one bug is a shared-fate event across tenants; a hardware-virtualization boundary gives each workload its own guest kernel and shrinks the exposed surface to a small virtio device model. Check the current documentation rather than trusting any comparison, including this one.

Can I pip install packages inside the sandbox on both?

In broad terms yes on both, because both give you a real filesystem and real processes rather than a language-level sandbox — that is precisely what separates this class of product from running code in a V8 isolate. The differences that matter are ergonomic rather than binary: where install time lands relative to your request path, whether you can bake a base image so the dependencies are already present, and how the installed state behaves between calls. E2B leans on an explicit template system for exactly this reason. On PandaStack, templates are baked into Firecracker snapshots and the guest ships with mise-managed Node, Python, Go and Bun pre-warmed, so an install is a normal apt/pip/npm problem. Confirm the current behaviour for whichever you pick before you assume it.

Does state persist between calls in these sandboxes?

This is the question most worth checking yourself, because the answer differs by product and by tier and it changes. Conceptually, Cloudflare's durable state belongs to the Durable Object, and the container's own disk should be treated as belonging to that instance's lifetime under the platform's hibernation and eviction rules. E2B's sandbox filesystem persists for the life of the session, which is what makes the install-then-iterate agent loop work at all. PandaStack sandboxes use a copy-on-write rootfs that persists for the sandbox's life, snapshots that capture both disk and memory, and durable volumes for state that must outlive the VM. Read each vendor's current persistence documentation before you store anything you would miss.

Is a microVM sandbox slow to start compared to edge compute?

Not if the boot path is designed for it. Cold-booting a VM is slow; restoring a pre-baked snapshot is not. PandaStack restores a baked Firecracker snapshot on every create, with the restore step itself around 49ms inside a p50 of 179ms end to end and a p99 around 203ms, and no warm pool of idle VMs. The only roughly 3-second boot is the very first spawn of a template before its snapshot exists, and forking a running sandbox with copy-on-write memory and a reflinked rootfs takes 400-750ms on the same host or 1.2-3.5s cross-host. What a microVM API cannot give you is edge adjacency: if your traffic already terminates at Cloudflare, calling any external sandbox vendor adds a network hop that no restore time compensates for.

Keep reading

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.