# Speed **A new Runtime sandbox runs its first command 0.81 seconds after you ask for it**, at the median, measured from a laptop over the public internet. The slowest of 30 took 1.06 seconds. These are times you would see from your own code, network included, not times taken on the server. Run the script at the end of this page to measure them from where you are. ## What we measured On 24 September 2026, at 00:09 UTC, one after another: | Step | Median | p95 | p99 | Samples | | -------------------------------------- | ------ | ------ | -------- | ------- | | Create, until the sandbox is running | 607 ms | 732 ms | 949 ms | 30 | | Create, until the first `echo` answers | 814 ms | 928 ms | 1,059 ms | 30 | | First `node -e` in a new sandbox | 219 ms | 265 ms | 410 ms | 30 | | First `python3 -c` in a new sandbox | 116 ms | 136 ms | 217 ms | 30 | | A command in a sandbox already in use | 105 ms | 149 ms | 216 ms | 100 | | Pause | 234 ms | 296 ms | 296 ms | 10 | | One API call (`GET /v1/me`), for scale | 90 ms | 232 ms | 232 ms | 10 | - **Where from:** a MacBook Pro (Apple M3 Pro, macOS) in the US Mountain time zone, on its usual connection, with Node 24.20.0 and `withruntime` 0.5.0 from npm. Opening a connection to the API took 67 ms, which is about one network round trip. Runtime runs in one region, in Virginia. - **What ran:** the free trial's default sandbox (2 vCPU, 4 GiB of memory, 4 GiB of disk, shared CPU), started from the default template, one at a time. Each was stopped before the next began. - **Percentiles:** p95 and p99 are nearest-rank. With 30 samples p99 is the slowest run; with 10, p95 and p99 are both the slowest. - **A second run:** a run four minutes earlier had medians within 6 per cent of these on every step. - **On the server:** measured on the host itself, with no network, a create took a median 270 ms on 22 September 2026. The client's connection to the API is opened before timing starts, as it would be in a program that has already made one call. A fresh process pays for that once, about 140 ms here. ## What others publish These are each provider's own figures. None says where it was measured from or whether the network is included, so they are not measured the same way as the table above. | Provider | What it publishes | Source | | ---------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------- | | Cloudflare Sandbox | Container cold starts "can often be in the 1-3 second range" | [Containers FAQ](https://developers.cloudflare.com/containers/faq/) | | CodeSandbox (Together) | A new VM from scratch in 2.7 s at p95; from a snapshot in 500 ms | [Together, 20 May 2025](https://www.together.ai/blog/code-sandbox) | Both were checked on 23 September 2026. Each is slower than Runtime's time to a first command, network included. ## Run it yourself The script below uses the published SDK and only free-trial sandboxes. It starts them one at a time and stops every one before it exits, Ctrl-C included. 1. Save it as `bench.mts` in an empty folder. 2. Run `npm install withruntime`. 3. Run `node bench.mts` (Node 22.18 or later) or `bun bench.mts`. It uses the key this machine saved with `npx withruntime login`, or `RUNTIME_API_KEY`. `RUNS`, `EXECS` and `CYCLES` set the sample counts; `OUT=result.json` also writes every raw sample. ```ts check // bench.mts: how fast Runtime sandboxes start and answer, measured from here. import { writeFileSync } from "node:fs"; import { arch, cpus, platform, release } from "node:os"; import { Runtime, VERSION, type Sandbox } from "withruntime"; const RUNS = Number(process.env.RUNS ?? 30); // fresh sandboxes const EXECS = Number(process.env.EXECS ?? 100); // commands in one warm sandbox const CYCLES = Number(process.env.CYCLES ?? 10); // pauses, resumes and forks const runtime = new Runtime(); const samples: Record = {}; const skipped: Record = {}; const live = new Set(); const record = (name: string, ms: number) => (samples[name] ??= []).push(ms); const code = (error: unknown) => { const { code, requestId } = error as { code?: string; requestId?: string }; return code ? `${code}${requestId ? ` (${requestId})` : ""}` : String(error); }; async function timed(name: string, work: () => Promise): Promise { const started = performance.now(); const value = await work(); record(name, performance.now() - started); return value; } async function start(): Promise { const sbx = await runtime.sandboxes.create({ funding: "trial", timeoutSeconds: 900 }); live.add(sbx); return sbx; } async function stop(sbx: Sandbox) { await sbx.stop({ wait: false }); live.delete(sbx); } async function stopAll() { for (const sbx of [...live]) await stop(sbx).catch(() => console.error(`Stop ${sbx.id}!`)); } process.once("SIGINT", () => void stopAll().finally(() => process.exit(130))); try { await runtime.me(); // opens the connection, as a long-lived client would have for (let i = 0; i < 10; i++) await timed("API round trip (GET /v1/me)", () => runtime.me()); for (let i = 0; i < RUNS; i++) { const began = performance.now(); const sbx = await timed("create → running", start); await sbx.exec("echo ready", { check: true }); record("create → first echo output", performance.now() - began); await timed("first node -e in a new sandbox", () => sbx.exec(["node", "-e", "console.log(1)"], { check: true }), ); await timed("first python3 -c in a new sandbox", () => sbx.exec(["python3", "-c", "print(1)"], { check: true }), ); await stop(sbx); } const sbx = await start(); for (let i = 0; i < 5; i++) await sbx.exec("echo warm"); for (let i = 0; i < EXECS; i++) await timed("exec round trip, warm sandbox", () => sbx.exec("echo hi", { check: true })); for (let i = 0; i < CYCLES && !skipped.pause; i++) await timed("pause", () => sbx.pause()).then( () => timed("resume → running", () => sbx.wake()), (error: unknown) => void (skipped.pause = code(error)), ); for (let i = 0; i < CYCLES && !skipped.fork; i++) { const copy = await timed("fork → copy running", () => sbx.fork()).catch(async (error) => { skipped.fork = code(error); const started = (error as { details?: { startedSandboxIds?: string[] } }).details; for (const id of started?.startedSandboxIds ?? []) live.add(await runtime.sandboxes.get(id)); }); if (copy) live.add(copy as Sandbox); if (copy) await stop(copy as Sandbox); } } catch (error) { console.error(`Stopped early: ${code(error)}`, error); process.exitCode = 1; } finally { await stopAll(); } const at = (sorted: number[], q: number) => sorted[Math.max(0, Math.ceil(q * sorted.length) - 1)]!; const rows = Object.entries(samples).map(([name, values]) => { const sorted = [...values].sort((a, b) => a - b); const ms = (q: number) => Math.round(at(sorted, q)); return { name, n: sorted.length, median: ms(0.5), p95: ms(0.95), p99: ms(0.99), max: ms(1) }; }); const client = `${platform()} ${release()} ${arch()}, ${cpus()[0]?.model ?? "unknown CPU"}`; const zone = Intl.DateTimeFormat().resolvedOptions().timeZone; const where = `${zone}, ${process.env.LOCATION ?? "location not given"}`; const engine = process.versions.bun ? `Bun ${process.versions.bun}` : `Node ${process.version}`; console.log(`${new Date().toISOString()}, withruntime ${VERSION}, ${engine}`); console.log(`Client: ${client}. Network: ${where}. API: ${runtime.transport.baseUrl}`); console.table(rows); for (const [name, reason] of Object.entries(skipped)) console.log(`Skipped ${name}: ${reason}`); if (process.env.OUT) writeFileSync(process.env.OUT, JSON.stringify({ client, where, rows, skipped, samples })); ```