Your agent just wrote 40 lines of Python. It wants to run them, read the output, fix the bug and run them again. Sooner or later every builder hits the same question: where does that code actually run?
If your answer is "on my API server, with exec()", you are one prompt injection away from rm -rf or a leaked .env. That's the reason sandboxes exist.
In this post I'll cover what an AI agent sandbox is and how the isolation works. Then I'll show how to plug one into an agent loop with TypeScript. After that comes the part I spent the most time on: every serious option, open-source and paid, with CPU and per-GPU pricing copied from each vendor's own page. I checked all prices on 25 October 2026.
If you want the company landscape first, I mapped it earlier in the companies building AI agent sandboxes, SDKs and APIs. This post is the priced follow-up.
The short answer
An AI agent sandbox is a short-lived, isolated computer that an agent can use to run code, install packages, read and write files and browse, without touching your servers, secrets or users' data. You create it through an API, the agent sends it commands as tool calls, you get back stdout, errors and files, and you destroy it when the task ends. A good one boots in milliseconds, bills per second, and limits CPU, memory, time and network access.
%%{init: {"theme":"base","fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","themeVariables":{"fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","fontSize":"15px","primaryColor":"#FFFFFF","primaryTextColor":"#1C1917","primaryBorderColor":"#1C1917","lineColor":"#78716C","edgeLabelBackground":"#FFFFFF","clusterBkg":"#FAFAF9","clusterBorder":"#D6D3D1"},"flowchart":{"curve":"basis","padding":14,"nodeSpacing":40,"rankSpacing":55}}}%%
flowchart LR
U["User task"]:::start e1@--> L["LLM agent"]:::accent
L e2@-->|"tool call: run this code"| S
subgraph S["Sandbox · a throwaway computer"]
direction TB
FS["Own filesystem"]:::muted
NET["Network allowlist"]:::muted
LIM["CPU, RAM and time limits"]:::muted
end
S e3@-->|"stdout, files, errors"| L
L e4@--> A["Final answer"]:::ok
S -.-x|"no access"| H["Your servers, keys, database"]:::bad
e1@{ animate: true }
e2@{ animation: fast }
e3@{ animation: fast }
e4@{ animate: true }
classDef accent fill:#E0E7FF,stroke:#4F46E5,stroke-width:2.5px,color:#1C1917,font-weight:bold
classDef start fill:#1C1917,stroke:#1C1917,color:#FFFFFF,font-weight:bold
classDef ok fill:#DCFCE7,stroke:#16A34A,stroke-width:2px,color:#14532D
classDef bad fill:#FEE2E2,stroke:#DC2626,stroke-width:2px,stroke-dasharray:5 4,color:#7F1D1D
classDef muted fill:#F5F5F4,stroke:#A8A29E,color:#57534EThe agent talks to the sandbox only through tool calls. The sandbox gets its own disk and a network allowlist, and it can never reach your keys or database.
Why agents need sandboxes now
Three things changed in the last year:
- Agents run code by default. Coding agents, data-analysis agents and "computer use" agents all need a real shell. OpenAI added native sandbox execution to its Agents SDK in April 2026, which shows where the default is heading.
- Prompt injection is a code-execution bug. A web page, a README or a PDF the agent reads can contain instructions. If the agent obeys and runs code on your host, the attacker runs code on your host. With a sandbox, that becomes a wasted minute instead of a breach.
- Parallel runs only work if environments are disposable. Running 50 agent attempts at once, or scoring a model on SWE-bench, needs 50 clean machines that start fast and die fast.
I wrote about why this layer turned into a battleground in the whole fight for the AI sandbox. Whoever owns the place where agents execute owns a big part of the agent stack.
Sandbox vs harness vs agent SDK
People mix these three up all the time:
| Layer | What it does | Examples |
|---|---|---|
| Agent SDK | The loop: call the model, parse tool calls, keep memory | OpenAI Agents SDK, Pydantic AI, smolagents |
| Harness | The scaffolding around the loop: tools, prompts, retries, evals | Claude Code, Codex, your own wrapper |
| Sandbox | The isolated machine the tools execute in | E2B, Daytona, Vercel Sandbox, microsandbox |
The SDK decides what to run. The sandbox decides where it's safe to run it. If the harness layer is new to you, read what an agent harness is. To pick the SDK itself, see my Python agent SDK comparison.
How sandbox isolation works
"Sandbox" covers everything from a Docker container to a full virtual machine. What matters is how much the code shares with your machine. The more it shares, the faster it starts and the easier it is to escape.
%%{init: {"theme":"base","fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","themeVariables":{"fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","fontSize":"15px","primaryColor":"#FFFFFF","primaryTextColor":"#1C1917","primaryBorderColor":"#1C1917","lineColor":"#78716C","edgeLabelBackground":"#FFFFFF","clusterBkg":"#FAFAF9","clusterBorder":"#D6D3D1"},"flowchart":{"curve":"basis","padding":14,"nodeSpacing":40,"rankSpacing":55}}}%%
flowchart LR
P["Subprocess or eval · shares your kernel"]:::bad e1@-->|"stronger"| C["Container · namespaces, seccomp"]:::muted
C e2@-->|"stronger"| G["gVisor · user-space kernel"]:::muted
G e3@-->|"stronger"| M["microVM · own kernel, boots in ms"]:::accent
M e4@-->|"stronger, slower"| V["Full VM"]:::muted
P1["exec() on your API server"]:::muted -.- P
C1["Docker, Podman, Claude Code srt"]:::muted -.- C
G1["Modal, Google gVisor"]:::muted -.- G
M1["E2B, Vercel Sandbox, microsandbox"]:::ok -.- M
e1@{ animation: slow }
e2@{ animation: slow }
e3@{ animation: slow }
e4@{ animation: slow }
classDef accent fill:#E0E7FF,stroke:#4F46E5,stroke-width:2.5px,color:#1C1917,font-weight:bold
classDef start fill:#1C1917,stroke:#1C1917,color:#FFFFFF,font-weight:bold
classDef ok fill:#DCFCE7,stroke:#16A34A,stroke-width:2px,color:#14532D
classDef bad fill:#FEE2E2,stroke:#DC2626,stroke-width:2px,stroke-dasharray:5 4,color:#7F1D1D
classDef muted fill:#F5F5F4,stroke:#A8A29E,color:#57534EEvery step to the right shares less with the host. MicroVMs are the sweet spot most agent platforms picked: a separate kernel per sandbox, with boot times close to a container's.
- Subprocess or
eval: zero isolation. Fine for code you wrote, never for code a model wrote. - Containers (Docker, Podman) use Linux namespaces and cgroups. They're fast, but every container shares the host kernel, so one kernel bug can mean an escape. Seccomp, dropped capabilities and no-new-privileges help. Anthropic's sandbox-runtime, which sits behind Claude Code's sandbox, uses bubblewrap and seccomp on Linux and Seatbelt on macOS.
- gVisor puts a user-space kernel between the code and the real kernel, so most system calls never reach the host. Modal uses it for its sandboxes.
- MicroVMs such as Firecracker and libkrun give each sandbox its own minimal kernel on a hardware hypervisor. E2B and Vercel Sandbox run on Firecracker, and microsandbox runs on libkrun.
- Full VMs isolate best but boot in seconds, which is too slow when an agent wants a fresh machine for every task.
My rule of thumb: use a microVM or gVisor for anything a model or a user wrote. A hardened container is fine for a local dev loop on your own machine, and that's about it.
How to use an AI agent sandbox
Every provider's SDK has the same shape. You create a sandbox, run code or commands in it, read the results, and kill it.
%%{init: {"theme":"base","fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","themeVariables":{"fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","fontSize":"15px","actorBkg":"#FFFFFF","actorBorder":"#1C1917","actorTextColor":"#1C1917","actorLineColor":"#D6D3D1","signalColor":"#44403C","signalTextColor":"#1C1917","noteBkgColor":"#E0E7FF","noteBorderColor":"#4F46E5","noteTextColor":"#1C1917","activationBkgColor":"#E0E7FF","activationBorderColor":"#4F46E5","sequenceNumberColor":"#FFFFFF","labelBoxBkgColor":"#FFFFFF","labelBoxBorderColor":"#A8A29E"}}}%%
sequenceDiagram
autonumber
participant App as Your app
participant LLM as LLM
participant SB as Sandbox provider
App->>SB: create(template, limits, allowlist)
SB-->>App: sandbox id, ready in ms
rect rgb(238, 242, 255)
loop until the task is done or step limit
App->>LLM: task + tools + last result
LLM-->>App: tool call run_python(code)
App->>SB: runCode(code)
SB-->>App: stdout, error or files
end
end
App->>SB: kill()
Note over App,SB: billing stops hereCreate once per task, loop the model's tool calls through the sandbox, and always kill it in a finally block. Billing stops on kill.
Step 1: run model-written code in E2B
The smallest useful example uses E2B's code interpreter, which keeps a Jupyter-style session so variables survive between calls.
import { Sandbox } from "@e2b/code-interpreter";
// Code an LLM wrote. Never run this with eval() on your own server.
const llmCode = `
import statistics
prices = [12, 15, 11, 30, 14]
print("median:", statistics.median(prices))
statistics.mean(prices)
`;
async function main() {
const sbx = await Sandbox.create({ timeoutMs: 5 * 60_000 }); // needs E2B_API_KEY
try {
const run = await sbx.runCode(llmCode);
if (run.error) {
console.error("code failed:", run.error.name, run.error.value);
return;
}
console.log("stdout:", run.logs.stdout.join(""));
console.log("last value:", run.text);
} finally {
await sbx.kill(); // stop paying the moment you're done
}
}
main();Step 2: build and test a repo in Vercel Sandbox, with the network locked down
Coding agents need a whole repo, a package install and a build. Vercel's SDK clones the repo straight into the sandbox. The networkPolicy is the line I care about most: it allows only the npm registry, so injected instructions can't send your code anywhere.
import { Sandbox } from "@vercel/sandbox";
async function main() {
// Auth comes from VERCEL_OIDC_TOKEN (run `vercel env pull` first).
const sandbox = await Sandbox.create({
source: { type: "git", url: "https://github.com/vercel/sandbox-example-next.git" },
resources: { vcpus: 2 },
timeout: 10 * 60_000,
// Only the npm registry is reachable: an injected prompt can't phone home.
networkPolicy: { allow: ["registry.npmjs.org", "*.npmjs.org"] },
});
try {
const install = await sandbox.runCommand("npm", ["ci"]);
if (install.exitCode !== 0) throw new Error(await install.stderr());
const build = await sandbox.runCommand("npm", ["run", "build"]);
console.log("exit", build.exitCode);
console.log(await build.stdout());
} finally {
await sandbox.stop();
}
}
main();Step 3: make it a tool your agent can call
This is the loop from the sequence diagram. The model goes through OpenRouter, and the sandbox hides behind a one-method interface, so you can swap E2B for Daytona, Modal or a self-hosted microsandbox without touching the agent. If you want the smallest possible version of this loop, I built one in the smallest AI agent.
import OpenAI from "openai";
// Any sandbox provider fits behind this one method.
export interface CodeSandbox {
run(code: string): Promise<{ stdout: string; error?: string }>;
close(): Promise<void>;
}
const tools: OpenAI.Chat.Completions.ChatCompletionTool[] = [
{
type: "function",
function: {
name: "run_python",
description: "Run Python in an isolated sandbox and return stdout or the error.",
parameters: {
type: "object",
properties: { code: { type: "string" } },
required: ["code"],
},
},
},
];
export async function agent(
llm: Pick<OpenAI, "chat">,
sandbox: CodeSandbox,
task: string,
model = "openai/gpt-4o-mini",
maxSteps = 6,
): Promise<string> {
const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
{ role: "system", content: "Solve the task. Use run_python to compute anything." },
{ role: "user", content: task },
];
try {
for (let step = 0; step < maxSteps; step++) {
const res = await llm.chat.completions.create({ model, messages, tools });
const msg = res.choices[0].message;
messages.push(msg);
if (!msg.tool_calls?.length) return msg.content ?? "";
for (const call of msg.tool_calls) {
if (call.type !== "function") continue;
const { code } = JSON.parse(call.function.arguments) as { code: string };
const out = await sandbox.run(code);
messages.push({
role: "tool",
tool_call_id: call.id,
content: out.error ? `ERROR: ${out.error}` : out.stdout.slice(0, 4000),
});
}
}
return "Stopped: step limit reached.";
} finally {
await sandbox.close();
}
}
// Real wiring: OpenRouter for the model, E2B for the sandbox.
export async function main() {
const { Sandbox } = await import("@e2b/code-interpreter");
const sbx = await Sandbox.create();
const sandbox: CodeSandbox = {
async run(code) {
const r = await sbx.runCode(code);
return { stdout: r.logs.stdout.join(""), error: r.error && `${r.error.name}: ${r.error.value}` };
},
close: () => sbx.kill().then(() => undefined),
};
const llm = new OpenAI({ baseURL: "https://openrouter.ai/api/v1", apiKey: process.env.OPENROUTER_API_KEY });
console.log(await agent(llm, sandbox, "What is the 30th Fibonacci number?"));
}What I tested: all three files typecheck against @e2b/code-interpreter 2.9.0, @vercel/sandbox 3.9.0 and openai 7.43.0. I ran the agent loop offline with a fake model and a local Python subprocess standing in for the sandbox. It made one tool call, got 832040 back, answered "The answer is 832040." and closed the sandbox in finally. I did not run the real E2B and Vercel calls, because they need API keys.
Step 4: understand the lifecycle (this is where the bill comes from)
%%{init: {"theme":"base","fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","themeVariables":{"fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","fontSize":"15px","primaryColor":"#FFFFFF","primaryTextColor":"#1C1917","primaryBorderColor":"#1C1917","lineColor":"#78716C","edgeLabelBackground":"#FFFFFF","clusterBkg":"#FAFAF9","clusterBorder":"#D6D3D1"},"state":{"padding":10}}}%%
stateDiagram-v2
direction LR
[*] --> Creating: create()
Creating --> Running: ready
Running --> Paused: pause() or idle
Paused --> Running: resume()
Running --> Snapshot: snapshot()
Snapshot --> Running: new sandbox from it
Running --> Killed: kill() or timeout
Paused --> Killed: TTL ends
Killed --> [*]
note right of Running: billed per second
note right of Paused: storage only
classDef live fill:#E0E7FF,stroke:#4F46E5,stroke-width:2.5px,color:#1C1917,font-weight:bold
classDef cheap fill:#DCFCE7,stroke:#16A34A,stroke-width:2px,color:#14532D
classDef dead fill:#F5F5F4,stroke:#A8A29E,color:#57534E
class Running live
class Paused,Snapshot cheap
class Killed,Creating deadRunning costs money every second. Paused and snapshotted sandboxes cost only storage, which is how long-lived agents stay cheap.
- Templates and snapshots: bake your dependencies into a template so
pip installdoesn't run (and bill) on every task. - Pause, don't idle: E2B pauses and resumes sandboxes, and a pause resets its session-length timer. Vercel's persistent sandboxes restore the filesystem between sessions. Daytona bills stopped sandboxes for disk only.
- Timeouts are a cost control: E2B Hobby caps a session at 1 hour (Pro at 24), and Vercel caps it at 45 minutes on Hobby (24 hours on Pro). Set your own shorter timeout anyway.
Open-source AI agent sandboxes you can self-host
Self-hosting makes sense when data can't leave your cloud, when you run enough sandboxes that the per-second markup hurts, or when you need a GPU type a vendor doesn't offer. I cloned each repo on 24 and 25 October 2026 and checked the licence and latest commit myself.
| Project | What it is | Isolation | Licence | Last commit | Best for |
|---|---|---|---|---|---|
| E2B infra + E2B SDK | The same stack E2B's cloud runs, self-hostable on GCP/AWS | Firecracker microVM | Apache-2.0 | 2026-10-24 | Teams that want E2B's API on their own cloud |
| microsandbox | Embeddable microVM SDK, keys stay outside the VM | libkrun microVM | Apache-2.0 | 2026-10-24 | Local-first agents, single servers |
| OpenSandbox (Alibaba) | General sandbox platform with multi-language SDKs | Container/VM runtimes | Apache-2.0 | 2026-10-24 | Kubernetes shops wanting a full platform |
| agent-sandbox (kubernetes-sigs) | Kubernetes CRD for isolated, stateful agent pods | Pluggable (gVisor, Kata) | Apache-2.0 | 2026-10-24 | Running sandboxes as native k8s objects |
| OpenShell (NVIDIA) | Policy-enforced agent runtime | Container + Landlock, seccomp, OPA proxy | Apache-2.0 | 2026-10-24 | Fine-grained policy on what agents may do |
| beta9 (Beam) | Beam's open-source serverless engine with sandboxes and GPUs | Containers on your GPU nodes | AGPL-3.0 | 2026-10-24 | Self-hosted GPU sandboxes |
| CubeSandbox | Fast KVM microVMs with E2B SDK compatibility | KVM microVM | Apache-2.0 | 2026-09-30 | Drop-in E2B-compatible self-hosting |
| agent-infra/sandbox | All-in-one box: browser, shell, VS Code, MCP | Docker container | Apache-2.0 | 2026-09-14 | Browser and computer-use agents |
| llm-sandbox | Python library to run LLM code in Docker/Podman/k8s | Containers | MIT | 2026-10-21 | Quick Python projects |
| sandbox-runtime (Anthropic) | Local sandbox behind Claude Code | bubblewrap/seccomp, Seatbelt | Apache-2.0 | 2026-10-23 | Sandboxing CLI agents on a laptop |
| gVisor / Firecracker | The building blocks most of the above use | User-space kernel / microVM | Apache-2.0 | 2026-10-24 / 2026-10-23 | Building your own platform |
| Daytona | Former open-source Daytona platform | Dedicated-kernel sandboxes | Last tagged licence, as is | 2026-06-25 | Forking only. See note |
Two warnings. Daytona's public repo now says core development moved to a private codebase in June 2026, so it gets no updates. Treat Daytona as a paid service, not an open-source one. Also, Arrakis (AGPL), which shows up on older lists, hasn't had a commit since June 2025. For a longer list of local tools, awesome-agent-sandbox tracks 25 projects.
Self-hosting isn't free. You pay for the nodes (bare metal or nested-virtualisation instances for Firecracker), warm pools, image caching, an egress proxy, and someone on call when a host fills up. Below a few thousand sandbox-hours a month, a hosted service is usually cheaper than an engineer's time.
Paid AI agent sandbox platforms: CPU pricing
All prices are list prices in USD, taken from each vendor's own pricing page or docs on 25 October 2026, except where marked.
| Platform | vCPU / hour | Memory / GB-hour | Billing model | Free tier / plan | GPU? |
|---|---|---|---|---|---|
| E2B | $0.0504 | $0.0162 (GiB) | Per second while running; paused = free | Hobby $0 + $100 one-time credit; Pro $150/mo | No |
| Daytona | $0.0504 | $0.0162 (GiB) | Per second; first 5 GiB storage free | $200 free credit; startups up to $50k | Yes |
| Modal Sandboxes | $0.1419 per physical core (= 2 vCPU) | $0.0240 (GiB) | Per second, non-preemptible rates (3× base) | Starter $30/mo credit; Team $250/mo | Yes |
| Vercel Sandbox | $0.128 per active CPU-hour | $0.0212 provisioned | CPU only while busy; memory for lifetime (1-min min) | Hobby: 5 CPU-h + 420 GB-h/mo; Pro uses $20 credit | No |
| Cloudflare Sandbox | $0.072 per active vCPU-hour | $0.009 (GiB) | 10 ms increments; fixed instance shapes | $5/mo Workers Paid incl. 375 vCPU-min, 25 GiB-h | No |
| Northflank | $0.01667 | $0.00833 | Per second, microVM sandboxes | $20/mo free resources | Yes |
| Runloop | Fixed sizes: 2 vCPU / 4 GB = $0.3195/h | (bundled) | While running or resuming | Trial | No |
| Beam Sandboxes | $0.135 per physical core (= 2 vCPU) | $0.023 (GiB) | Per millisecond | Developer $20/mo incl. $20 credit | Yes |
| Thunder Compute | $0.051 | $0.016 (GiB) | Per second, non-preemptible | Not stated | Yes |
| Fly.io Sprites | $0.0385 (used) | $0.0219 (used) | Metered on actual use; idle = storage only | Hero plan $100/mo with included hours | No |
| Blaxel* | Bundled by memory tier: 4 GB = $0.1656/h | (bundled) | Per second, auto-standby after 1–5 s idle | Up to $200 starting credit | No |
*Blaxel's tier prices come from Northflank's May 2026 pricing comparison, which is a competitor's article. Blaxel's own per-second metering post gives a range of $0.000006 to $0.0000115 per GB-second, without a per-tier list. Check blaxel.ai/pricing before you rely on these.
Here's the same 2 vCPU / 4 GB machine for one hour on each platform:
%%{init: {"theme":"base","fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","themeVariables":{"fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","xyChart":{"backgroundColor":"#FFFFFF","titleColor":"#1C1917","xAxisLabelColor":"#44403C","yAxisLabelColor":"#44403C","xAxisTitleColor":"#1C1917","yAxisTitleColor":"#1C1917","xAxisLineColor":"#A8A29E","yAxisLineColor":"#A8A29E","plotColorPalette":"#059669"}},"xyChart":{"width":1100,"height":460,"xAxis":{"labelFontSize":13},"yAxis":{"labelFontSize":13}}}}%%
xychart-beta
title "One hour of a 2 vCPU / 4 GB sandbox (USD, list price)"
x-axis ["Northflank", "Vercel 10% CPU", "Fly Sprites", "E2B", "Daytona", "Thunder", "Beam", "Modal", "Runloop", "Vercel 100% CPU"]
y-axis "USD per hour" 0 --> 0.4
bar [0.067, 0.110, 0.165, 0.166, 0.166, 0.166, 0.227, 0.238, 0.320, 0.341]Vercel shows up twice because it bills CPU only while it's busy. Agents spend most of their time waiting on the LLM, so the 10% bar is the realistic one. Cloudflare is left out because it has no 4 GB shape; its 2 vCPU / 8 GiB standard-3 costs about $0.22 at full CPU.
GPU sandboxes: pricing per GPU-hour
Most agent sandboxes are CPU-only. E2B, Vercel, Cloudflare, Runloop, Blaxel and Fly Sprites don't list GPUs. When your agent has to run a model, fine-tune, render video or score evals on a GPU, these are the options:
| GPU | Modal | Daytona (on-demand / spot) | Northflank | Beam (serverless / VM) | Thunder | RunPod Pods | Koyeb* |
|---|---|---|---|---|---|---|---|
| B200 | $6.25 | $6.25 / $3.59 | $5.87 (8× only) | – / $4.11 | – | – | – |
| H200 | $4.54 | $4.54 / $2.61 | $3.14 (8× only) | – / $2.09 | – | $5.29 | – |
| H100 | $3.95 | $3.95 / $2.27 | $2.74 (8× only) | $3.50 / $1.83 (PCIe) | $2.95 | $3.99 SXM, $2.89 PCIe | $2.50 |
| A100 80 GB | $2.50 | – | $1.76 | – / $1.36 | $1.95 | $1.79 | $1.60 |
| A100 40 GB | $2.10 | – | $1.42 | – | – | – | – |
| L40S | $1.95 | – | – | – / $0.76 | – | $1.09 | $1.20 |
| RTX PRO 6000 | $3.03 | $3.03 / $1.74 | $3.00 | – / $1.09 | – | – | – |
| L4 | $0.80 | – | $0.80 | – | – | $0.59 | – |
| RTX 4090 | – | $0.99 / $0.57 | – | $0.69 / $0.44 | – | $0.89 | – |
How to read it:
- Modal's hourly figures are my own arithmetic. Modal lists per-second prices (an H100 is $0.001097/s, which works out to $3.95/h). CPU and memory are billed on top.
- Northflank's rate bundles GPU, CPU and RAM, but its pricing page lists H100, H200 and B200 only as 8-GPU containers, so one H100 for an hour isn't an option there.
- Daytona's "spot" column is its preemptible tier. The GPU can be taken back, so only use it for jobs that checkpoint.
- Beam's VM prices are "from" prices for on-demand machines. Its serverless rates (per second, scale to zero) are higher.
- RunPod and Koyeb are GPU clouds rather than agent-sandbox SDKs, but many teams run their own sandbox runtime on them. *Koyeb's prices come from its November 2025 price-cut post, so check the current page. RunPod's are from its pricing page.
- "–" means the GPU isn't listed, not that it's impossible.
%%{init: {"theme":"base","fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","themeVariables":{"fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","xyChart":{"backgroundColor":"#FFFFFF","titleColor":"#1C1917","xAxisLabelColor":"#44403C","yAxisLabelColor":"#44403C","xAxisTitleColor":"#1C1917","yAxisTitleColor":"#1C1917","xAxisLineColor":"#A8A29E","yAxisLineColor":"#A8A29E","plotColorPalette":"#4F46E5"}},"xyChart":{"width":1100,"height":460,"xAxis":{"labelFontSize":13},"yAxis":{"labelFontSize":13}}}}%%
xychart-beta
title "Cheapest listed H100 price per hour (USD, Oct 2026)"
x-axis ["Beam VM", "Daytona spot", "Koyeb", "Northflank", "RunPod PCIe", "Thunder", "Beam serverless", "Modal", "Daytona", "RunPod SXM"]
y-axis "USD per GPU-hour" 0 --> 4.5
bar [1.83, 2.27, 2.50, 2.74, 2.89, 2.95, 3.50, 3.95, 3.95, 3.99]The cheapest H100 is roughly half the price of the most expensive, but the cheap ones are VMs or preemptible. Billing per second with scale to zero (Modal, Beam serverless, Daytona on-demand) costs more per hour and less in total for short, bursty agent jobs.
What it actually costs: three workloads
Here are real monthly numbers with the arithmetic shown, at list prices.
A. Hobby agent: 50 runs a day, 2 minutes each, 1 vCPU / 2 GB. That's 100 minutes a day, or 50 hours a month.
- E2B: 50 h × ($0.0504 + 2 × $0.0162) = $4.14/month, so the $100 credit lasts about two years.
- Vercel Hobby: at 10% CPU that's 50 × 0.1 = 5 CPU-hours and 50 × 2 = 100 GB-hours, inside the free 5 CPU-h and 420 GB-h. $0, though you'd sit exactly at the CPU cap.
- Modal Starter: 50 × ($0.1419 × 0.5 + 2 × $0.024) ≈ $5.95, covered by the $30 monthly credit. $0.
B. Production coding agent: 1,000 runs a day, 5 minutes each, 2 vCPU / 4 GB. That's 5,000 minutes a day, or about 2,500 sandbox-hours a month.
| Platform | Math | Monthly |
|---|---|---|
| Northflank | 2,500 × ($0.0333 + $0.0333) | $167 |
| Cloudflare (standard-3, 10% CPU) | CPU 2,500 × 2 × 0.1 × $0.072 = $36; memory 2,500 × 8 × $0.009 = $180; disk ≈ $10; + $5 plan | ≈ $231 |
| Vercel (10% CPU) | CPU 2,500 × 2 × 0.1 × $0.128 = $64; memory 2,500 × 4 × $0.0212 = $212; − $20 Pro credit | ≈ $256 |
| E2B | 2,500 × $0.1656 = $414, + $150 Pro for 24 h sessions and 100 concurrent | $414–$564 |
| Daytona | 2,500 × $0.1656 | $414 (first $200 free) |
| Modal | 2,500 × $0.2379 = $595, − $30 credit | $565 |
| Beam | 2,500 × $0.2272 = $568, + $20 plan, − $20 credit | $568 |
| Runloop (MEDIUM) | 2,500 × $0.3195 | $799 |
The Cloudflare and Vercel numbers leave out request and network charges, and they assume the agent is busy only 10% of the time. A CPU-heavy build agent at 100% CPU roughly doubles Vercel's bill.
C. GPU eval job: one H100 for 40 hours a month.
Beam VM (PCIe) $73 → Daytona spot $91 → Koyeb $100 → RunPod PCIe $116 → Thunder $118 → Beam serverless $140 → Modal or Daytona on-demand $158 (Modal adds CPU and RAM on top) → RunPod SXM $160.
On a small bill the gap between platforms hardly matters. On a big bill it's thousands of dollars, so before you commit, plug your own numbers into StackBudget, the open-source cost calculator I built. I follow the same habit for this site, which I wrote about in how we keep ihatereading.in under $100 a month.
Feature matrix
| E2B | Daytona | Modal | Vercel | Cloudflare | Northflank | Runloop | Beam | microsandbox (OSS) | |
|---|---|---|---|---|---|---|---|---|---|
| Isolation | Firecracker | Dedicated kernel (per README) | gVisor | Firecracker | Cloudflare Containers | microVM | ? | ? | libkrun |
| GPU | ✗ | ✓ | ✓ | ✗ | ✗ | ✓ | ✗ | ✓ | ✗ |
| Pause / resume or snapshots | ✓ | ✓ | ? | ✓ persistent | ? | ? | ✓ suspend | ✓ snapshots | ? |
| Network allowlist | ✓ | ? | ? | ✓ | ? | ? | ? | ? | ? |
| Max session (free / paid) | 1 h / 24 h | ? | ? | 45 min / 24 h | ? | ? | ? | ? | your hardware |
| Self-host | ✓ (infra repo) | ✗ (since June 2026) | ✗ | ✗ | ✗ | BYOC | ✗ | ✓ (beta9) | ✓ |
| SDKs | Python, JS/TS | Python, TS | Python (+ others) | TS | TS | API, CLI | Python, TS | Python | see repo |
A "?" means I couldn't confirm that item from the vendor's own pricing or docs pages. Plenty of these platforms probably have the feature, but this table only marks what I verified. Ask the vendor before you rely on a "?" cell.
How to choose an AI agent sandbox
%%{init: {"theme":"base","fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","themeVariables":{"fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","fontSize":"15px","primaryColor":"#FFFFFF","primaryTextColor":"#1C1917","primaryBorderColor":"#1C1917","lineColor":"#78716C","edgeLabelBackground":"#FFFFFF","clusterBkg":"#FAFAF9","clusterBorder":"#D6D3D1"},"flowchart":{"curve":"basis","padding":14,"nodeSpacing":40,"rankSpacing":55}}}%%
flowchart TB
S["Your agent needs to run code"]:::start e1@--> Q1{"Need a GPU?"}:::accent
Q1 e2@-->|"yes"| G["Modal, Daytona, Northflank, Beam, Thunder Compute"]:::ok
Q1 e3@-->|"no"| Q2{"Data must stay on your infra?"}:::accent
Q2 -->|"yes"| O["Self-host: E2B infra, microsandbox, OpenSandbox, agent-sandbox"]:::ok
Q2 e4@-->|"no"| Q3{"Already on Vercel or Cloudflare?"}:::accent
Q3 -->|"yes"| V["Vercel Sandbox or Cloudflare Sandbox"]:::ok
Q3 e5@-->|"no"| Q4{"Long sessions or heavy parallel runs?"}:::accent
Q4 -->|"yes"| L["Northflank, Daytona, Runloop"]:::ok
Q4 e6@-->|"no, just run snippets"| E["E2B code interpreter"]:::ok
e1@{ animate: true }
e2@{ animation: fast }
e3@{ animate: true }
e4@{ animate: true }
e5@{ animate: true }
e6@{ animate: true }
classDef accent fill:#E0E7FF,stroke:#4F46E5,stroke-width:2.5px,color:#1C1917,font-weight:bold
classDef start fill:#1C1917,stroke:#1C1917,color:#FFFFFF,font-weight:bold
classDef ok fill:#DCFCE7,stroke:#16A34A,stroke-width:2px,color:#14532D
classDef bad fill:#FEE2E2,stroke:#DC2626,stroke-width:2px,stroke-dasharray:5 4,color:#7F1D1D
classDef muted fill:#F5F5F4,stroke:#A8A29E,color:#57534EStart from the hardest constraint: GPU, then where your data must live, then what you already run.
- You only need to run snippets for a chatbot or data agent: E2B's code interpreter, or Vercel Sandbox's free tier if you're on Vercel already.
- You run a coding agent at scale: price Northflank, Cloudflare and Vercel first. Active-CPU billing suits agents that mostly wait on the LLM.
- Your agent needs a GPU: Modal for the smoothest per-second, scale-to-zero experience; Daytona or Beam for cheaper H100s; Thunder for simple flat GPU rates.
- Data can't leave your cloud: self-host E2B infra or microsandbox, or run kubernetes-sigs/agent-sandbox with gVisor on your own cluster.
- You need a browser or computer-use agent: pick a template with Chromium preinstalled (agent-infra/sandbox is a good open-source start) and keep the egress allowlist tight.
Production checklist
%%{init: {"theme":"base","fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","themeVariables":{"fontFamily":"Inter, ui-sans-serif, system-ui, sans-serif","fontSize":"15px","primaryColor":"#FFFFFF","primaryTextColor":"#1C1917","primaryBorderColor":"#1C1917","lineColor":"#78716C","edgeLabelBackground":"#FFFFFF","clusterBkg":"#FAFAF9","clusterBorder":"#D6D3D1"},"flowchart":{"curve":"basis","padding":14,"nodeSpacing":40,"rankSpacing":55}}}%%
flowchart LR
U["User"]:::start e1@--> API["Your API · keys live here"]:::accent
API e2@<--> LLM["LLM provider"]:::muted
API e3@--> CP["Sandbox control plane"]:::muted
CP e4@--> POOL["Warm pool from a template"]:::accent
POOL e5@--> PX["Egress proxy · allowlist"]:::accent
PX --> NET["npm, PyPI, approved APIs"]:::ok
PX -.-x BAD["Everything else"]:::bad
POOL --> SNAP[("Snapshots, artifacts")]:::muted
POOL --> LOG["Logs, traces, cost per run"]:::muted
e1@{ animate: true }
e2@{ animation: fast }
e3@{ animate: true }
e4@{ animate: true }
e5@{ animation: slow }
classDef accent fill:#E0E7FF,stroke:#4F46E5,stroke-width:2.5px,color:#1C1917,font-weight:bold
classDef start fill:#1C1917,stroke:#1C1917,color:#FFFFFF,font-weight:bold
classDef ok fill:#DCFCE7,stroke:#16A34A,stroke-width:2px,color:#14532D
classDef bad fill:#FEE2E2,stroke:#DC2626,stroke-width:2px,stroke-dasharray:5 4,color:#7F1D1D
classDef muted fill:#F5F5F4,stroke:#A8A29E,color:#57534EKeys stay in your API, sandboxes come from a warm pool, and all egress goes through an allowlist proxy. Every run leaves logs and a cost line.
- Never put long-lived secrets in the sandbox. Pass short-lived, scoped tokens, or proxy calls through your API.
- Deny network by default and allowlist package registries and the APIs the task needs.
- Set three limits on every run: wall-clock timeout, step limit in the agent loop, and output size, so a runaway
printcan't fill your context window. - Kill in
finally. Orphaned sandboxes are the most common surprise bill. - Use templates or snapshots so dependencies install once, not per run.
- Log every command and its cost per run. You'll need it for debugging and, more and more, for audits. See AI agent auditing and compliance.
- Re-check prices every quarter. Sandbox pricing is young and moves fast.
Myths and gotchas
- "Docker is a sandbox." It's isolation, but every container shares the host kernel. For untrusted, model-written code, use gVisor or a microVM.
- "Per-second billing means I only pay for work." Not always. E2B, Daytona and Modal bill for reserved resources while the sandbox runs, even when it's waiting on the LLM. Vercel, Cloudflare and Fly Sprites bill CPU on actual use instead.
- "Open source means free." Self-hosting moves the bill to servers and an on-call engineer. It pays off at scale or under data-residency rules, rarely before.
- "The cheapest H100 is the cheapest option." A $1.83 VM that runs all month costs more than a $3.95 per-second GPU that runs 40 hours.
FAQ
What is an AI sandbox? An isolated, disposable environment where AI-generated code runs safely. It has its own filesystem, network rules and resource limits, and it's separate from your servers and data.
Is E2B open source? Yes. Both the E2B SDK and the infrastructure behind E2B's cloud are on GitHub under Apache-2.0, and you can self-host the infra repo.
What is the best free AI agent sandbox? Hosted: Vercel Sandbox Hobby (5 active CPU-hours a month), E2B Hobby ($100 one-time credit) and Daytona ($200 credit). Self-hosted: microsandbox or E2B infra.
Which AI sandboxes support GPUs? Modal, Daytona, Northflank, Beam and Thunder Compute offer GPU sandboxes. E2B, Vercel Sandbox, Cloudflare Sandbox, Runloop and Fly Sprites are CPU-only today.
How much does an H100 sandbox cost per hour? On 25 October 2026, list prices ran from $1.83/h (Beam on-demand PCIe VM) to $3.99/h (RunPod H100 SXM). Modal and Daytona on-demand are $3.95/h.
E2B vs Daytona vs Modal: which should I pick? E2B for the simplest code-interpreter API, Daytona if you need GPUs at E2B-like CPU prices, and Modal if you want per-second GPUs with scale to zero and you're happy in Python.
Where to go next
- The companies building AI agent sandboxes, SDKs and APIs, the landscape this post prices out
- Python agent SDKs compared, to pick the loop that calls your sandbox
- Every post on the ihatereading blog, or the monthly roundup in the magazine
Prices are list rates checked on 25 October 2026 from each vendor's own pricing page unless marked otherwise. They change often, so verify before you commit.