# How to fork a running sandbox into parallel copies Call `sbx.fork({ count })` for up to 10 running copies with the source's files, memory and processes, all answered in one call. **On Runtime a fork copies a live machine, not just its disk: a server that was running in the source is still running in every copy.** The snapshot the fork takes for itself is deleted when the fork ends and is never billed, so three waiting 2 vCPU, 4 GiB copies cost 3 × $0.03125, about $0.094 an hour, and nothing more (rates checked 25 September 2026, [pricing](/docs/pricing)). Copies run on the source's server. ## Fork a machine with a server running Start the work once, fork, and each copy carries on from that moment: ```ts check import { Sandbox } from "withruntime"; await using base = await Sandbox.create(); await base.exec("pip install --quiet requests", { timeoutMs: 120_000 }); await base.spawn("python3 -m http.server 8000", { cwd: "/workspace" }); const copies = await base.fork({ count: 3, labels: { experiment: "retry-policy" } }); for (const copy of copies) { const probe = await copy.exec("curl -s -o /dev/null -w '%{http_code}' localhost:8000"); console.log(copy.id, probe.stdout); // 200: the server came along } await Promise.all(copies.map((copy) => copy.stop())); ``` ```python check from withruntime import Sandbox with Sandbox.create() as base: base.exec("pip install --quiet requests", timeout_ms=120_000) base.spawn("python3 -m http.server 8000", cwd="/workspace") copies = base.fork(count=3, labels={"experiment": "retry-policy"}) for copy in copies: probe = copy.exec("curl -s -o /dev/null -w '%{http_code}' localhost:8000") print(copy.id, probe.stdout) for copy in copies: copy.stop() ``` ```bash no-run runtime sandbox fork "${id}" --count 3 runtime sandbox fork "${id}" --count 3 --paid --keep-snapshot ``` With `count`, `fork` returns a list; without it, one sandbox. The source is paused for the moment the fork takes, about a second for a fresh sandbox and longer the more memory it holds, then woken. A paused source stays paused. ## Options | Option | Default | What it does | | ---------------- | ------------ | ------------------------------------------------------------------------------------ | | `count` | one copy | How many copies, 1 to 10 | | `funding` | the source's | `"trial"` or `"paid"`, as on a create | | `name`, `labels` | none | Handles for the copies | | `keepSnapshot` | `false` | Keep the fork's snapshot to start more copies later; then billed as snapshot storage | | MCP | — | `runtime_sandbox_fork` | Each copy gets the source's vCPUs, memory, disk and CPU setting (reserved CPU, or a raised floor), and is billed as a create of that size would be. ## When a copy fails A fork that fails after its snapshot answers with the failing step's error. The copies that did start are in `details.startedSandboxIds`, and they keep running, and billing, until you stop them. ```ts check import { RuntimeError, Sandbox } from "withruntime"; const base = await Sandbox.create(); try { const copies = await base.fork({ count: 5 }); console.log(copies.map((copy) => copy.id)); } catch (error) { if (!(error instanceof RuntimeError)) throw error; const started = (error.details?.startedSandboxIds ?? []) as string[]; for (const id of started) await (await Sandbox.connect(id)).stop(); console.log(error.code, error.hint); } ``` A failed fork is over. The same idempotency key answers the same error, so fork again with a new key ([idempotency keys](/how-to/retry-safely-with-idempotency-keys)). ## Limits and refusals | Case | What happens | | --------------------------------------------- | ------------------------------------------------------------------------ | | Trial copies past eight running at once | `trial_busy`; more copies than the trial runs never fit | | Source with reserved CPU or a floor above 250 | Copies cannot fit the trial, so it forks only onto `"paid"` | | Source created with `pausable: false` | `not_pausable`: a fork pauses its source, so it cannot be forked | | `fork_unavailable` (503) | Switched off there on purpose; retrying will not help | | Fork stopped partway, source left paused | The source stays paused; a `fork-left-paused` notice says how to wake it | A paid account runs 100 sandboxes at once to start, so ten copies of several sources fit comfortably ([how many at once](/docs/pricing#how-many-at-once)). ## Where forking pays off - **Trying several fixes.** A coding agent reaches a failing test with the repo built and the dev server up, then forks one copy per candidate fix ([coding agent sandbox](/use-cases/coding-agent-sandbox)). - **Sampling answers.** Run the same prepared environment against several model outputs and keep the best ([RL environments](/use-cases/rl-environments)). - **Evaluation episodes.** Every episode starts from exactly the same memory and process state ([agent evals](/use-cases/agent-evals-and-swe-bench)). ## Mistakes to avoid - **Forgetting the copies.** Each copy is a sandbox with its own lease, billed until it stops or pauses. Stop each one when its attempt is done, even after an error. - **Forking for later.** Copies start now. To start copies next week, take a [snapshot](/how-to/snapshot-a-sandbox), or pass `keepSnapshot: true`. - **Retrying a trial fork that asks for too many.** More copies than the trial's eight at once never fit, however long you wait. Ask for fewer, or pass `funding: "paid"`. The idea behind forks is explained in [what is a sandbox fork?](/glossary/sandbox-fork). Facts on this page were checked on 25 September 2026.