Vercel Sandbox vs Cloudflare's Sandbox SDK
On paper these two are the same product. You install an SDK, you call something that hands you a machine, you write a file into it, you run a command, you read stdout as it arrives, and if the process opened a port you get a URL that points at it. Vercel Sandbox does that. Cloudflare's Sandbox SDK — the code-execution layer that sits on Cloudflare Containers and is addressed through Durable Objects — does that. Both will happily run the Python your model wrote thirty seconds ago, which is the entire job description.
Here's the thing nobody says out loud in these comparisons: neither of these is a sandbox company. Both are a feature of a very large platform, built for people already on that platform — which isn't a criticism, it's the single most useful fact about the decision. You are rarely choosing between them on the merits of the sandbox; you are ratifying a decision you made a year ago about where your application lives. So the productive question isn't "which sandbox is better," it's "what does each one's parent platform make cheap, and is that what my workload needs?"
I'm Ajay. I built PandaStack, which is also in this category, so read this with the appropriate squint. My rule for these posts is: specific and numeric about my own platform, qualitative about everyone else's, because I won't publish a benchmark of a product I don't operate. There's one clearly-labelled PandaStack section near the end that you're welcome to skip, and a verdict section where the honest answer for most readers is "use the one your app already runs on."
What each one actually is
Vercel Sandbox is ephemeral compute, publicly described as microVM-backed, sold as a primitive of the Vercel platform. The mental model is a job: ask for a machine, get a fresh one, do a unit of work, it goes away. It slots naturally into the thing Vercel customers were already doing badly — an agent generates a project and somebody has to `npm install` and build it somewhere that isn't the request handler. Logs and lifecycle land in a surface your team already has open.
Cloudflare's Sandbox SDK is a layer over Cloudflare Containers, reached from a Worker, with the sandbox's identity and lifecycle hanging off a Durable Object. The mental model is not a job — it's an object with a name. You don't get a handle back from a create call so much as you ask for the sandbox called `user-1234` and get it, whether or not it existed a moment ago. That's a genuinely different primitive, and it happens to be exactly the shape of "this user's workspace" or "this agent's long-running session."
Vercel's sandbox is shaped like a build step. Cloudflare's is shaped like an object with a name. Your workload is already one of those two shapes, and you probably know which.
Almost everything below falls out of that difference. Job-shaped compute is easy to reason about and easy to leave, because there was never any state to migrate. Entity-shaped compute fits agent sessions far better and commits you far harder, because the addressing scheme and the platform's rules about when things sleep become load-bearing parts of your architecture.
Isolation: what boundary are you buying?
This is where vendors reach for adjectives and readers reach for a blog post as evidence, so let me be brief. Vercel publicly describes Sandbox as microVM-backed ephemeral compute — hardware-virtualized, its own guest kernel. Cloudflare's sandbox runs on their container platform, materially stronger than the V8 isolates behind Workers since you get a real filesystem, real processes and arbitrary binaries; the specific tenancy guarantees are theirs to state, not mine to guess. Both are reasonable categories of answer, and neither should be settled by me.
The question I'd actually ask, and the one that tends to produce useful silence: is the isolation boundary a product commitment or an implementation detail? An implementation detail can be swapped in a release you never read about. A written commitment can't. If your compliance story depends on "hardware virtualization between tenants," you need that sentence in a versioned document, not a launch post.
It deserves ten minutes rather than a checkbox because model-generated code is untrusted code in the formal sense — an LLM that confidently emits a recursive delete against the wrong path isn't a hypothetical, it's a Tuesday. A container is, in the end, a polite suggestion to a kernel that is also serving somebody else. Shared kernel: one bug is a shared-fate event. Hypervisor: the attacker's target shrinks to a small virtio device model.
The programming model: create, exec, stream, expose
Strip the branding off and both SDKs implement the same five verbs. Get a machine. Put a file in it. Run a command. Stream the output, because a four-minute build with no output is indistinguishable from a hang to whoever is watching the spinner. Get a URL for a port the process opened. Then throw the machine away.
// ILLUSTRATIVE PSEUDOCODE -- this is the SHAPE both SDKs implement, not the
// real method names of either one. Read the current docs before copying.
async function runGeneratedCode(source: string) {
// 1. Get a machine. Vercel hands you a fresh ephemeral one; Cloudflare
// hands you the one that belongs to this id, creating it if needed.
const box = await sandbox.get({ id: "agent-42", timeoutMs: 10 * 60_000 });
try {
// 2. Put the model's output somewhere that is not your API process.
await box.writeFile("/work/step.py", source);
// 3. Run it, and STREAM. Buffering the whole log until exit is the
// single most common way these integrations feel broken in demos.
const proc = await box.startCommand("python", ["/work/step.py"]);
for await (const chunk of proc.stdout) process.stdout.write(chunk);
const { exitCode } = await proc.wait();
// 4. If it started a server, hand back a URL pointing at the port.
const url = exitCode === 0 ? await box.exposePort(3000) : null;
return { exitCode, url };
} finally {
// 5. The unglamorous line that keeps the invoice unglamorous.
await box.stop();
}
}The difference that bites is step 1. A create call that returns an opaque handle is fine right up until your Node process restarts mid-job and the handle is gone — now you have an orphaned machine billing you and no way to reattach. Naming the sandbox yourself makes reconnect trivial: ask for `agent-42` again. Cloudflare's Durable Object identity gives you that for free, and it's a genuinely underrated ergonomic win. On a handle-based API you persist the id next to your job row and write the reaping loop yourself. Either way somebody writes that loop; the question is whether it's you.
Port exposure is table stakes on both, and it's what turns a sandbox from a code-runner into a preview environment — the model wrote a Next.js app, it's running on 3000 inside the box, and the user wants to click it. Check two things on whichever you pick: whether the URL is authenticated or effectively public-if-guessed, and how long it survives relative to the sandbox. Those answers decide whether "share a preview with a teammate" is a feature or an incident.
Session lifetime, sleep, and what survives
This is the axis that most often forces a migration nine months in, so read the limits page before you write the loop. Vercel Sandbox is job-shaped and bounded — there's a documented maximum duration, and you should look it up for your plan before designing a 40-minute build around it. Cloudflare's model is entity-shaped, so the interesting behaviour isn't a hard ceiling so much as the rules about when an idle instance sleeps, what wakes it, and what a wake costs. I won't quote either number; it may be stale by the time you read this.
The question to ask isn't "how long can it run." It's: when my agent comes back after eleven minutes of the user thinking, does it find the same machine with the same virtualenv and the same half-finished checkout, or nothing at all? Agent loops are bursty and human-paced, and the install-then-iterate pattern only works if the environment survives to the second call. The honest failure mode of job-shaped compute is re-installing three gigabytes of wheels every turn and calling it a cold-start problem when it's really a lifetime problem.
Filesystem, egress, and where the thing physically runs
Both give you a real filesystem and real processes, which is the entire reason this class of product exists rather than just running the code in a V8 isolate. So `pip install` works on both, and the interesting question is ergonomic: where does install time land relative to your request path, and can you bake a base image so the answer is "nowhere"? Persistence is where they diverge — on the Vercel side treat disk as scratch and mean it; on the Cloudflare side durable state is the Durable Object's job, and the container's own disk belongs to that instance's lifetime under the platform's sleep and eviction rules.
Egress quietly decides most serious evaluations and gets the least attention. The question isn't "does the sandbox have internet access" — it does, that's the point — it's "can I express a policy?" Can I say: this box may reach PyPI and our model endpoint and nothing else? Cloudflare is a network company, which cuts both ways; ask them specifically what policy you can express for sandbox egress rather than assuming the Workers-era answers apply, and ask Vercel the same question in the same written form. Coarser-than-expected egress control on managed compute is the most common unpleasant surprise at security review.
Regional placement gets a paragraph because people optimise the wrong hop. Vercel's placement follows its region model; Cloudflare's follows their network, though container-capable locations aren't automatically everywhere a Worker runs — verify both. But the sandbox usually isn't talking to your end user. It's talking to your database, your object store and a model API, so the latency that matters is sandbox-to-those, not sandbox-to-browser. I've watched teams pick a provider for edge proximity and then discover their agent's real cost was forty round trips to a Postgres instance three thousand kilometres away.
Pricing shape (not pricing numbers)
I won't print anyone's numbers, including my own — they change monthly and a blog post is the worst place to learn them. The shape is what's durable. Both price like platform compute: metered resources folded into the same account and invoice as the rest of your usage, which is either delightful consolidation or an unattributable line item depending on whether your finance team wants to know what code execution costs on its own. If that conversation is coming, tag your usage from day one; retrofitting attribution onto a blended platform bill is a miserable quarter.
The costs people actually get surprised by aren't the compute rate. They're: idle time you're paying for because a sandbox stayed alive waiting for a user who left; egress, which is where sandbox workloads that pull large datasets get expensive fast, and where the two parent platforms have famously different philosophies; and the re-install tax, where you pay compute repeatedly to rebuild an environment you could have baked once. Model those three against your real agent traffic. They dominate the rate card.
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, because both move fast.
- Core shape — Vercel Sandbox: job-shaped ephemeral compute; ask for a machine, do a unit of work, throw it away. Cloudflare Sandbox SDK: entity-shaped; a named sandbox whose lifecycle hangs off a Durable Object. PandaStack: session-shaped and long-lived — it runs until its TTL expires, you kill it, or the idle reaper takes it, and persistent sandboxes are exempt from the reaper.
- Isolation boundary — Vercel Sandbox: publicly described as microVM-backed ephemeral compute; confirm the current tenancy statement with them. Cloudflare Sandbox SDK: runs on their container platform — real filesystem and processes, a materially stronger model than Workers isolates; ask them for the specific tenancy guarantee in writing. 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.
- How you get one — Vercel Sandbox: a create call returning a handle, so reconnect-after-crash is yours to solve. Cloudflare Sandbox SDK: get-by-id via a Durable Object, so reattaching is trivial and genuinely underrated. PandaStack: create returns an id you own, reattachable from any process, because the control plane is a plain REST API rather than a runtime binding.
- Streaming output — Vercel Sandbox: streamed through the SDK. Cloudflare Sandbox SDK: streamed through the Worker, which folds naturally into an SSE response you're already sending a browser. PandaStack: streaming exec over SSE plus a WebSocket PTY, so "give the user a real terminal" is one endpoint rather than a project.
- Exposing a port — Vercel Sandbox: a URL that fronts the port your process opened; check its auth model and lifetime. Cloudflare Sandbox SDK: a preview URL through their network; same two questions. PandaStack: tokenless per-sandbox preview hosts of the form port-id.suffix, where the sandbox UUID is the credential and the URL lives as long as the sandbox does.
- Filesystem persistence — Vercel Sandbox: treat disk as scratch; the box is gone at session end. Cloudflare Sandbox SDK: durable state belongs to the Durable Object, and the container's disk to that instance's lifetime under the platform's sleep and eviction rules. PandaStack: copy-on-write rootfs for the sandbox's life, snapshots capturing disk and memory, durable volumes for state that must outlive the VM.
- Egress control — Vercel Sandbox: ask what policy you can actually express; managed-compute egress is often coarser than security review expects. Cloudflare Sandbox SDK: you're inside a network company's network, which cuts both ways — ask specifically about sandbox egress rather than assuming Workers-era answers. PandaStack: per-sandbox netns, veth pair and NAT rules, which is the layer where allow-list egress is enforceable rather than aspirational.
- Regional placement — Vercel Sandbox: follows their region model. Cloudflare Sandbox SDK: follows their network, though container-capable locations aren't necessarily everywhere a Worker runs; verify. PandaStack: you pick the region, and if the answer needs to be your own datacentre, the same agent binary runs on your KVM hosts under Apache-2.0.
- Vendor gravity — Vercel Sandbox: highest if your app deploys to Vercel, near-zero if it doesn't. Cloudflare Sandbox SDK: highest if your app is Workers-native with state in Durable Objects, awkward if not. PandaStack: none — a REST API and SDKs that assume nothing about where your app runs, which is a benefit or a shrug depending on whether you wanted gravity.
- Pricing shape — Vercel Sandbox and Cloudflare Sandbox SDK: both metered as platform compute on the same invoice as everything else you buy from them; consolidation or unattributability, your call. PandaStack: usage-based on what 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 vendor-gravity question, answered plainly
Here's the part where a comparison post is supposed to build tension and then declare a winner. I'm not going to, because for most readers the answer is boring and correct: use the one your app already runs on.
If your product deploys to Vercel and your team lives in that dashboard, Vercel Sandbox costs you approximately one import statement. If your requests terminate at Cloudflare and your per-user state is already in Durable Objects, the Sandbox SDK is addressed by the same ID scheme as everything else you've built — no second control plane, no second key to rotate, no second status page to care about at 3am. In both cases a third-party sandbox vendor buys you an extra on-call rotation and an outbound hop in exchange for advantages you may not need. Integration gravity is a real engineering asset when it pulls in the direction you were already walking.
Gravity stops being an asset at exactly three moments, and they're the whole reason this category has more than two players. When the platform's duration rules don't fit your workload — a long build, a multi-hour job, a session that must survive many human-paced turns. When the isolation boundary stops being a preference and becomes a compliance artifact you must produce for a customer. And when you need to run this in your own account, at which point both options exit the conversation by definition. If none of those apply, close the tab and use what you've got.
Where a dedicated Firecracker platform differs (yes, this is the PandaStack bit)
Clearly labelled so you can skip it. PandaStack is a different bet from both: not a feature of a platform you deploy to, but a standalone API whose design centre is the isolation boundary and the fork primitive. Every sandbox is its own Firecracker microVM with its own guest kernel and its own network namespace.
The standing objection to per-sandbox VMs is that they're slow to start. That's a boot-path problem, not a virtualization problem, and it's the thing we actually built. There's no warm pool of idle VMs; every create restores a pre-baked snapshot on demand. The restore step itself is about 49ms, inside a p50 of 179ms and a p99 of 203ms end to end. The only roughly 3-second boot is the very first spawn of a template, before its snapshot has been baked — after that, it's restores all the way down.
The primitive neither of the other two offers in the same form is fork. Branch a running sandbox — copy-on-write memory, reflinked rootfs — in 400-750ms on the same host, or 1.2-3.5s cross-host. That converts "the model proposed three different fixes" from three cold sandboxes that each re-install the same wheels into three live machines that all start from the exact state where the failure happened. It's the difference between re-running an experiment and branching it, and once your agent loop has it, going back feels like losing undo.
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.
sbx = Sandbox.create(template="code-interpreter", ttl_seconds=900)
try:
# The model wrote this. Nobody has read it. That is precisely why it
# is running over there instead of inside your API process.
sbx.filesystem.write("/work/main.py", model_output)
setup = sbx.exec("pip install pandas pyarrow", timeout_seconds=300)
if setup.exit_code != 0:
raise RuntimeError(setup.stderr)
# Freeze the machine WITH the dependencies installed, so the next turn
# starts warm instead of re-downloading three gigabytes of wheels.
checkpoint = sbx.snapshot()
# Three candidate fixes, three live branches of the SAME failed state.
# Copy-on-write memory + reflinked disk: 400-750ms each, same host.
branches = []
for candidate in model_candidates:
b = sbx.fork()
b.filesystem.write("/work/main.py", candidate)
branches.append((candidate, b))
for candidate, b in branches:
r = b.exec("python /work/main.py", timeout_seconds=120)
print(r.exit_code, r.stdout[:400])
b.kill() # reap every branch, win or lose
finally:
sbx.kill()The same shape in TypeScript, minus the fork, for the create-exec-stream-kill path most people start with:
import { Sandbox } from "@pandastack/sdk";
const sandbox = await Sandbox.create({
template: "code-interpreter",
ttlSeconds: 900,
});
try {
await sandbox.filesystem.write("/work/main.py", source);
// Stream stdout/stderr as it happens -- a silent four-minute build is
// indistinguishable from a hang to whoever is watching the spinner.
for await (const evt of sandbox.execStream("python /work/main.py")) {
if (evt.type === "stdout") process.stdout.write(evt.data);
if (evt.type === "stderr") process.stderr.write(evt.data);
if (evt.type === "exit") console.log("exit", evt.exitCode);
}
} finally {
await sandbox.kill();
}Now the honest trade-off, because a comparison post that only lists advantages is an advert. If your app is already Vercel-native or Workers-native, calling us means an outbound hop from your platform to ours, a second vendor, a second key to rotate and a second status page to watch. Neither Vercel's build-and-preview integration nor Cloudflare's edge adjacency is something I can sell you, and no amount of restore-latency bragging changes that. Pick us for the boundary, the fork primitive and long-lived stateful sandboxes — not for platform gravity, which we deliberately don't have.
When all of this is overkill
I'd rather you skipped the evaluation entirely than cargo-culted it. If the code you're running is your own — a build step, a data transform, a scheduled job — you don't have an untrusted-code problem and none of this applies. Run it in a container on whatever you already operate. The isolation argument earns its keep exactly when the code's author is a model, a customer, or a stranger on the internet, and not one minute before.
If you do have that problem but your workloads are short, stateless and low-volume — run a snippet, show the output, done — take the platform-native option and move on. The gap between these products at that workload is measured in things you'll never notice. Reach for a dedicated sandbox platform when at least one of these is true: sessions that are long or must survive across turns, branching execution state rather than replaying it, egress policy as a requirement, an isolation boundary you must hand a customer as a document, or running the whole thing in your own account. Plenty of good products never hit any of it.
Whatever you pick, do the thing that actually settles it: build the smallest workload that would embarrass you in production and run it on each candidate. Install your two ugliest dependencies, run your longest realistic job, try to reach an endpoint you're supposed to be blocked from, expose a port and see who can reach the URL, then kill everything and check whether anything survived. Time each step from the region you'll actually deploy to. Then write the forty-line wrapper — create, exec, writeFile, destroy — and make it a rule that nothing else imports a vendor SDK directly. Given how fast all three of us are moving, that hour is the highest-confidence recommendation here.
Frequently asked questions
What is the difference between Vercel Sandbox and Cloudflare's Sandbox SDK?
Vercel Sandbox is job-shaped ephemeral compute, publicly described as microVM-backed: you ask for a machine, do a unit of work, and it goes away. Cloudflare's Sandbox SDK is entity-shaped — it runs on Cloudflare Containers, is reached from a Worker, and its identity and lifecycle hang off a Durable Object, so you address a named sandbox rather than holding an opaque handle. That makes Cloudflare a natural fit for long-lived per-user or per-agent workspaces, and Vercel a natural fit for build-and-preview style jobs. Both are features of a larger platform, so integration gravity usually decides it. Verify current limits and behaviour in each vendor's own docs, because both move fast.
Which one is safer for running untrusted AI-generated code?
Vercel publicly describes Sandbox as microVM-backed, meaning a hardware-virtualization boundary with its own guest kernel. Cloudflare's sandbox layer runs on their container platform, which is materially stronger than the V8 isolates behind Workers since you get a real filesystem and real processes, but the specific tenancy guarantee is theirs to state. Both are reasonable categories of answer and neither should be settled by a blog post. The question worth asking each vendor is whether the isolation boundary is a product commitment or an implementation detail — an implementation detail can change in a release you never read about, while a written commitment can't. If it's a compliance artifact, get it in a versioned document.
Does the sandbox filesystem persist between calls on either platform?
Treat Vercel Sandbox disk as scratch — it is ephemeral by design and the machine is gone when the session ends. On Cloudflare, 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 sleep and eviction rules. This matters more than it sounds, because the install-then-iterate agent loop only works if the environment is still there on the second call; otherwise you pay to reinstall dependencies on every turn. PandaStack sandboxes use a copy-on-write rootfs that persists for the sandbox's life, snapshots that capture disk and memory together, and durable volumes for state that must outlive the VM.
Is a microVM sandbox slower to start than platform-native compute?
Not if the boot path is built 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 of 203ms, and no warm pool of idle VMs. The only roughly 3-second boot is the first-ever spawn of a template, before its snapshot exists. Forking a running sandbox takes 400-750ms same-host or 1.2-3.5s cross-host. What an external API can't give you is platform adjacency: if your traffic already terminates at Vercel or Cloudflare, calling out adds a hop no restore time compensates for.
Should I just use whichever platform my app is already on?
Usually, yes. If you deploy to Vercel or your requests terminate at Cloudflare, the platform-native sandbox costs roughly one import statement, inherits your existing auth and observability, and adds no second vendor, key or status page. Gravity stops being an asset at three moments: when the platform's duration rules don't fit your workload, when the isolation boundary becomes a compliance artifact you must hand a customer rather than a preference, or when you must run execution in your own account. If none of those apply, take the native option and spend the saved week on your product.
Keep reading
- Vercel Sandbox vs E2B — the platform-native vs standalone version of this trade-off
- Cloudflare Sandbox SDK vs E2B — the same question from the Workers and Durable Objects side
- PandaStack vs Vercel Sandbox — a head-to-head on isolation, lifetime and forking
- Best code execution sandboxes for AI agents — the wider field if neither platform-native option fits
49ms p50 cold start. Fork, snapshot, and scale to zero.