Skip to content
Guides · Benchmarks

How Fast Are Burst Sandbox Creates? 20 and 40 at Once, Measured

Updated October 31, 2026 .md

Short answer: Measured on sandboxer.com production, Oct 31 2026, client in Ashburn VA, create→ready: 20 default sandboxes started at once in us-east were all ready with a p50 of 0.76 s and a max of 0.82 s; 40 at once with no region had a p50 of 1.87 s and a max of 2.00 s.

Results vary with load, region and where your client is. This page has one run of each burst size, with the method and the script so you can rerun it.

Results#

Label: measured on sandboxer.com production, Oct 31 2026, client in Ashburn VA, create→ready. Size default (4 vCPU, 8 GB). Times are per sandbox, from the create call to ready.

Burst Region Ran in p50 p90 max All ready in
20 at once us-east (requested) 20 in us-east 0.76 s 0.81 s 0.82 s 0.83 s
40 at once none given (the API picks) 30 in us-east, 10 in eu-central 1.87 s 1.96 s 2.00 s 2.01 s

The 40-at-once run, split by region:

Region Sandboxes p50 p90 max
us-east (nearest) 30 1.90 s 1.97 s 2.00 s
eu-central (regionSource: "burst") 10 0.63 s 0.87 s 0.87 s

All 60 sandboxes became ready; none failed.

How to read these numbers#

  • Both bursts were served from warm pools, sandboxes booted ahead of time. A burst bigger than the free warm pools includes cold boots and takes longer, so don't extrapolate to larger bursts.
  • One run each, at a quiet hour. These aren't averages over many runs, and other traffic can change them.
  • The client sat in the same data center as us-east, so the network distance to us-east was about zero. From elsewhere, add your round-trip time.
  • Ready means the sandbox can run a command. It doesn't include running one, a setup script or cloning repos.
  • Why 10 landed in eu-central: the 40-at-once run gave no region, and once us-east's free sandboxes were taken the rest went to the other region. Each of those reports regionSource: "burst". Pass region to keep a burst in one region; see regions.

Method#

  • Client: one Linux host in Ashburn, Virginia, in the same data center as the us-east region.
  • Firing: raw HTTPS calls to the public REST API, no SDK or CLI. A Python 3 script (standard library only) starts N threads and releases them together with a barrier. Each thread sends POST /api/v1/sandboxes with "type": "default" (plus "region": "us-east" for the 20 run, no region for the 40), then GET /api/v1/sandboxes/{id}?waitFor=ready.
  • Ready: the moment that GET answers. The server holds it open until the sandbox can run a command, which is how the SDKs, the CLI and MCP wait too. The time is the wall clock from just before the POST to that answer.
  • Cleanup: each sandbox was deleted as soon as it was timed.
  • When: Saturday, October 31, 2026: the 40 run at 11:15 UTC and the 20 run at 11:16 UTC, on shared production with no special setup.

Rerun it#

You need an API key that can create, read and delete sandboxes (see API keys), and a plan whose limit on sandboxes at once is at least N (see limits).

export SANDBOXER_API_KEY=sbx_…
python3 bench-burst.py -n 20 --type default --region us-east
python3 bench-burst.py -n 40 --type default

It prints p50, p90 and max overall and per region, and deletes every sandbox as it goes. The script:

bench-burst.py
#!/usr/bin/env python3
"""bench-burst.py: N sandbox creates fired at once, each timed from its create call to ready.

    SANDBOXER_API_KEY=… python3 bench-burst.py [-n 20] [--type default] [--region us-east] [--api https://sandboxer.com/api/v1]

Each worker thread sends POST /sandboxes, then GET /sandboxes/{id}?waitFor=ready (the server answers the moment
the sandbox can run a command; the SDKs, CLI and MCP do the same), and records the wall time from just before the
create to the ready answer. All N creates are released together by a barrier. Each sandbox is deleted the moment it
is timed (or after --give-up seconds without becoming ready), so the test holds capacity for seconds, not minutes.
Prints p50/p90/max overall and per region the sandboxes landed in.
"""
import argparse
import json
import os
import statistics
import threading
import time
import urllib.request

ap = argparse.ArgumentParser()
ap.add_argument("-n", type=int, default=20)
ap.add_argument("--type", default="default")
ap.add_argument("--region", default="")
ap.add_argument("--api", default="https://sandboxer.com/api/v1")
ap.add_argument("--give-up", type=float, default=90, help="seconds before a create that isn't ready is deleted")
args = ap.parse_args()
key = os.environ["SANDBOXER_API_KEY"]


def call(method, path, body=None, headers=None, timeout=120):
    req = urllib.request.Request(args.api + path, method=method, data=json.dumps(body).encode() if body is not None else None)
    req.add_header("Authorization", "Bearer " + key)
    req.add_header("Content-Type", "application/json")
    req.add_header("User-Agent", "sandboxer-bench-burst/1")
    for k, v in (headers or {}).items():
        req.add_header(k, v)
    try:
        with urllib.request.urlopen(req, timeout=timeout) as r:
            return r.status, json.load(r)
    except urllib.error.HTTPError as e:
        try:
            return e.code, json.load(e)
        except Exception:
            return e.code, {}


results = [None] * args.n
barrier = threading.Barrier(args.n)


def worker(i):
    body = {"type": args.type, "ttlSeconds": 900, "name": f"bench-{int(time.time())}-{i}"}
    if args.region:
        body["region"] = args.region
    barrier.wait()
    t0 = time.monotonic()
    code, r = call("POST", "/sandboxes", body)
    sb = r.get("sandbox") or {}
    if code >= 300 or not sb.get("id"):
        results[i] = {"ok": False, "error": (r.get("error") or {}).get("code", code)}
        return
    created = time.monotonic() - t0
    sid = sb["id"]
    state = sb.get("state")
    while state not in ("running", "ready", "error", "cancelled", "failed") and time.monotonic() - t0 < args.give_up:
        code, r = call("GET", f"/sandboxes/{sid}?waitFor=ready", timeout=max(5, args.give_up - (time.monotonic() - t0)))
        sb = r.get("sandbox") or sb
        state = sb.get("state")
        if code >= 300:
            break
    elapsed = time.monotonic() - t0
    call("DELETE", f"/sandboxes/{sid}", headers={"X-Sandboxer-Confirm-Delete": sid})  # free its room at once
    results[i] = {"ok": state in ("running", "ready"), "id": sid, "s": elapsed, "accepted": created,
                  "region": sb.get("region"), "source": sb.get("regionSource"), "state": state}


threads = [threading.Thread(target=worker, args=(i,)) for i in range(args.n)]
wall0 = time.monotonic()
for t in threads:
    t.start()
for t in threads:
    t.join()
wall = time.monotonic() - wall0


def pct(xs, p):
    xs = sorted(xs)
    return xs[min(len(xs) - 1, max(0, round(p / 100 * len(xs) + 0.5) - 1))]


def line(label, rs):
    ts = [r["s"] for r in rs]
    return f"{label:<22} n={len(ts):<4} p50 {statistics.median(ts):6.2f} s  p90 {pct(ts, 90):6.2f} s  max {max(ts):6.2f} s"


ok = [r for r in results if r and r["ok"]]
bad = [r for r in results if not r or not r["ok"]]
print(f"{args.n} x {args.type} creates at once{' in ' + args.region if args.region else ' (no region given)'}: {len(ok)} ready, {len(bad)} failed; all ready in {wall:.2f} s")
if ok:
    print(line("all", ok))
    for reg in sorted({r["region"] for r in ok}):
        rs = [r for r in ok if r["region"] == reg]
        srcs = ",".join(sorted({str(r["source"]) for r in rs}))
        print(line(f"{reg} ({srcs})", rs))
for r in bad[:10]:
    print("failed:", r)
print("deleted", sum(1 for r in results if r and r.get("id")), "(each as soon as it was timed)")

What this means for your code#

  • Fire creates in parallel. Each create is answered independently, so a loop that waits for one sandbox before creating the next is the slow part. The sub-second creates guide shows parallel creates with the SDKs.
  • Pin a region when it matters. Without region, a burst can spill to the other region. That's faster than waiting, but your sandboxes then run farther from you or your data.
  • Measure from where your code runs. Add your own round trip to these numbers, or run the script from your host.

FAQ#

How long does it take to start 20 sandboxes at once?#

In our run (measured on sandboxer.com production, Oct 31 2026, client in Ashburn VA, create→ready), 20 default sandboxes in us-east were all ready within 0.83 s, with a p50 of 0.76 s.

Why did some sandboxes in the 40 run start in eu-central?#

No region was given, so after the free us-east sandboxes were taken the API placed the rest in eu-central and marked them regionSource: "burst". Pass region to keep every sandbox in one region.

Does ready include running my setup?#

No. Ready means the sandbox can run a command. Setup scripts, repo clones and your first command come after.

Can I run this benchmark myself?#

Yes. Copy the script above, set SANDBOXER_API_KEY and run it with -n no larger than your plan's limit on sandboxes at once. It deletes each sandbox as soon as it's timed.

More guides

Top AI sandbox platforms for code execution in 2026, ranked

For running AI-written code we rank Sandboxer, Freestyle and E2B first: each gives code its own VM with an API or SDK and can pause with memory. Pick Daytona for Windows or GPUs, Modal or Northflank for GPUs at scale, E2B or Northflank to run in your own cloud, and Vercel Sandbox if your app lives on Vercel.

Read the guide
Best sandboxes for running coding agents (Claude Code, Codex, Gemini CLI) in 2026, ranked

For coding agents we rank Sandboxer first: a full Ubuntu VM with Claude Code and Codex preinstalled, Docker, and stop-and-resume that keeps the agent's session in memory. Freestyle and Amp Orbs also keep memory across pauses. Pick E2B for prebuilt agent templates on open source, Docker Sandboxes for free local runs, and Codespaces if you live in GitHub.

Read the guide
Best Daytona sandbox alternatives in 2026, ranked

The best Daytona alternatives depend on why you're switching. For a full Linux microVM on every sandbox with memory-saving stop and Docker, we rank Sandboxer first. E2B suits open source and self-hosting, Modal massive short-job fleets, Northflank bring-your-own-cloud with GPUs, and Vercel Sandbox apps on Vercel.

Read the guide
Best E2B alternatives in 2026, ranked

If you're leaving E2B for longer sessions or a fuller machine, we rank Sandboxer first, then Freestyle: both give each sandbox a full Linux VM that keeps memory across pauses, with Docker and no short session cap. Pick Daytona for Windows or GPUs, Northflank for bring-your-own-cloud, and stay on E2B if you need open source.

Read the guide