Every agent that writes code needs somewhere to run it. That space has become a product category with at least a dozen vendors, four incompatible billing models, and marketing pages that quote cold starts measured under conditions nobody publishes.
This comparison fixes the units. It covers the five platforms most teams shortlist — E2B, Daytona, Modal Sandboxes, Cloudflare Sandbox SDK, and Vercel Sandbox — along with Runloop, Fly.io Sprites, and Northflank where they change the answer.
The four questions that actually decide this
Feature matrices for this category are mostly noise. Four properties change architecture, and everything else is a preference:
- Cold start under concurrency: An agent loop that creates a sandbox per tool call pays this tax thousands of times a day.
- Filesystem persistence between turns: Does turn 2 see the pip install from turn 1, or does the agent rebuild its world?
- Egress policy: Can the sandbox reach the internet, can you turn that off, and can you change your mind mid-session?
- Idle billing: Agents spend most of their wall-clock waiting on a model. Somebody is paying for those seconds.
1. Cold start: what the numbers actually say
The vendor claims are not comparable to each other. Daytona’s pricing page advertises sub-90ms sandbox creation. E2B is commonly cited at roughly 150ms. Modal advertises sub-second cold starts for pre-cached containers. None of these state concurrency, region, image size, or whether the clock stops at API acknowledgment or at first executed command.
The most useful public dataset is ComputeSDK’s sandbox leaderboard, which is open source and runs on a schedule. It measures Time to Interactive (TTI): elapsed time from create() to the first successful command inside the sandbox, 100 iterations per provider, launched concurrently in a single burst, from a 4 vCPU host in Northern Virginia.
Results from the August 21, 2026 run:
| Provider | Median TTI | P95 | P99 | Success rate |
|---|---|---|---|---|
| Vercel Sandbox | 0.67s | 1.04s | 1.12s | 100% |
| Modal | 0.88s | 1.00s | 1.08s | 100% |
| Runloop | 0.89s | 3.27s | 3.50s | 100% |
| E2B | 1.61s | 1.77s | 1.81s | 100% |
| Cloudflare | 5.06s | 6.04s | 6.48s | 100% |
| Daytona | 0.27s | 0.43s | 0.44s | 37% |
Three things in that table matter more than the ranking.
- Burst is not the same test as sequential: Daytona’s fastest published median is real, and on an earlier provider-page run it created sandboxes at a 0.10s median when launched one at a time. On the August burst run it posted the fastest median in the field and completed 37 of 100 attempts. A median you only reach on a third of your calls is not a latency number, it is a capacity number. Retry logic is not optional on any of these platforms.
- Tail latency is the number to design against: Runloop’s median and Modal’s median are 10ms apart. Runloop’s P95 is 3.3x Modal’s. If your agent’s UX budget is one second, the median tells you almost nothing.
- Cloudflare is measuring a different product: Sandbox SDK sits on Cloudflare Containers, which schedules a container instance and boots an image. That is architecturally a heavier operation than resuming a pre-warmed Firecracker VM, and 5s medians reflect it. Cloudflare’s own GA post is candid about the shape of the problem: booting a sandbox, cloning a repo, and running npm install takes about 30 seconds, while restoring the same environment from a backup takes about two.
Reproducing this yourself
The task worth measuring is the one your agent runs, not echo hello. A useful harness runs the same unit of work everywhere: install pandas, read a CSV, plot it, return a PNG. Time four checkpoints separately.
# checkpoints: t_create -> t_ready -> t_deps -> t_result
# run 100 iterations sequential, then 100 concurrent, report median/P95/P99
import time, statistics
def one_run(provider):
t0 = time.perf_counter()
sbx = provider.create() # API acknowledged
t1 = time.perf_counter()
sbx.exec("python -c 'print(1)'") # first command returns: TTI
t2 = time.perf_counter()
sbx.exec("pip install pandas matplotlib")
t3 = time.perf_counter()
sbx.exec("python /work/plot.py") # writes /work/out.png
png = sbx.read_file("/work/out.png")
t4 = time.perf_counter()
sbx.kill()
return dict(create=t1-t0, tti=t2-t0, deps=t3-t2, task=t4-t3, bytes=len(png))Report tti and task separately. Vendors optimize the first and readers care about the second. Pin the region, pin the image, and publish both the sequential and the concurrent series, because they answer different questions.
2. Per-second pricing, normalized
Published rates as of August 27, 2026, converted to a common unit. Modal prices per physical core, which it defines as 2 vCPU, so the vCPU-equivalent is shown for comparison.
| Platform | CPU | Memory | Billing basis | Plan floor |
|---|---|---|---|---|
| E2B | $0.0504 / vCPU-hr | $0.0162 / GiB-hr | Wall-clock, per second | Free Hobby; $150/mo Pro |
| Daytona | $0.0504 / vCPU-hr | $0.0162 / GiB-hr | Wall-clock, per second | None; $200 credit |
| Modal Sandbox | $0.1419 / core-hr (~$0.0710 / vCPU-hr) | $0.0240 / GiB-hr | max(request, actual), per second | Free Starter; $250/mo Team |
| Vercel Sandbox | $0.128 / vCPU-hr active CPU only | $0.0212 / GB-hr provisioned | Split: CPU active, memory wall-clock | Hobby allotment; Pro credit |
| Cloudflare Sandbox | $0.072 / vCPU-hr active CPU only | $0.009 / GiB-hr provisioned | Active CPU + provisioned memory/disk | $5/mo Workers Paid |
| Fly.io Sprites | $0.07 / CPU-hr | $0.04375 / GB-hr | Active use only; sleeps when idle | Subscription tiers |
| Runloop | $0.108 / CPU-hr | $0.0252 / GB-hr | Running state; suspended is storage-only | Free Basic; $250/mo Pro |
| Northflank | $0.01667 / vCPU-hr | $0.00833 / GB-hr | Allocated resources, per second | Free Sandbox tier |
Two footnotes that people get wrong.
Source Read original →



