# How to snapshot a sandbox and start new ones from it Call `sbx.snapshot({ name, retentionDays })`, then `sandboxes.create({ snapshot: id })` to start a new sandbox as that machine. **On Runtime a snapshot keeps the whole machine, memory and running processes included, and is copied off its server, encrypted, as soon as it is ready, at no extra charge.** A snapshot costs $0.08 per decimal GB per 30-day month on the bytes it alone stores, and blocks two of your snapshots share count once (rate in force since 23 September 2026, [pricing](/docs/pricing#snapshots-images-and-volumes)). Set a machine up once, and every later task skips the clone, the install and the build. ## Prepare once, start many ```ts check import { Runtime, Sandbox } from "withruntime"; const runtime = new Runtime(); const base = await Sandbox.create(); await base.exec("git clone --depth 1 https://github.com/pallets/flask /workspace/flask", { timeoutMs: 120_000, }); await base.exec("pip install --quiet -e /workspace/flask", { timeoutMs: 300_000 }); const snapshot = await base.snapshot({ name: "flask-ready", retentionDays: 30 }); await base.stop(); // Any time in the next 30 days, from any process: for (const task of ["fix-1", "fix-2", "fix-3"]) { await using sbx = await runtime.sandboxes.create({ snapshot: snapshot.id, labels: { task }, }); console.log(task, (await sbx.exec("python3 -c 'import flask; print(flask.__name__)'")).stdout); } ``` ```python check from withruntime import Runtime runtime = Runtime() base = runtime.sandboxes.create() base.exec("git clone --depth 1 https://github.com/pallets/flask /workspace/flask", timeout_ms=120_000) base.exec("pip install --quiet -e /workspace/flask", timeout_ms=300_000) snapshot = base.snapshot(name="flask-ready", retention_days=30) base.stop() for task in ["fix-1", "fix-2", "fix-3"]: with runtime.sandboxes.create(snapshot=snapshot["id"], labels={"task": task}) as sbx: print(task, sbx.exec("python3 -c 'import flask; print(flask.__name__)'").stdout) ``` ```bash no-run snap=$(runtime sandbox snapshot "${id}" --name flask-ready --retention 30) runtime sandbox create --snapshot "${snap}" runtime snapshot ls ``` A sandbox started from a snapshot takes the snapshot's shape: its vCPUs, memory and disk. It is a new sandbox with its own id, billed as any other. ## What taking one does - **A running source** is paused for the moment the snapshot takes, about a second for a fresh sandbox and longer the more memory it holds, then woken. - **A paused source** stays paused. Snapshotting a paused sandbox is how you keep it as a template while it waits. - **The snapshot lives on its source's server**, where sandboxes started from it run, and its copy off that server is what lets it survive the server. ## Durability, state by state | `durability.state` | Meaning | | ------------------ | -------------------------------------------------------------------- | | `pending` | Being copied off the server | | `durable` | Copied, read back and checked; `backedUp` is `true` | | `restoring` | Its server was lost; it is being restored onto another from its copy | | `failed` | It could not be copied; `error` says why | | `none` | A fork's own snapshot, deleted when the fork ends and never copied | While a snapshot is `restoring`, a create or fork from it answers 503 `snapshot_restoring`. Try again in a few minutes; the snapshot comes back on a server in its region ([storage](/docs/storage#snapshots-survive-their-server)). ## Options and limits | Setting | Default | Range or rule | | -------------------- | ------- | ------------------------------------------------------------ | | `retentionDays` | 7 | 1 to 365; delete sooner with `snapshots.delete` | | `name`, `labels` | none | Your own handles for finding it again | | Source with volumes | — | Refused: a sandbox with volumes cannot be snapshotted | | `snapshot` on create | — | Not together with `image` | | Trial storage | — | Snapshots are not part of the trial's free storage | | MCP | — | `runtime_snapshot_create`, `runtime_snapshot_get`, `_delete` | ## Snapshot, pause or fork? - **[Pause](/how-to/pause-and-resume-a-sandbox)** when you want the same sandbox back. Each pause replaces the previous saved state. - **Snapshot** when you want new sandboxes from one moment, today and next week, as many as you like. - **[Fork](/how-to/fork-a-running-sandbox)** when you want running copies now. A fork takes its own snapshot and deletes it when it ends, so it is free. - **[An image](/how-to/build-an-image-from-a-recipe)** when files are enough and nothing in memory matters. ## Mistakes to avoid - **Keeping snapshots forever by accident.** Each is charged for as long as it is kept. Pick a `retentionDays` that matches the job, and delete a snapshot you have replaced: `runtime.snapshots.delete(snapshot.id)`. - **Snapshotting a sandbox with volumes.** It is refused. Keep the volume's data on the volume, snapshot a sandbox without it, and attach the volume to each copy ([volumes](/how-to/attach-a-volume)). - **Snapshotting mid-write.** A running source is paused for a moment and its memory kept, so a process in the middle of work carries on in each copy. For a clean starting point, let setup finish first. - **Secrets in the snapshot.** Whatever the source held in its files and memory, every copy holds. Give code API keys as [secrets sandboxes never see](/docs/security#secrets-sandboxes-never-see): a copy holds only the placeholder, never the key. Snapshots suit [agent evals and SWE-bench](/use-cases/agent-evals-and-swe-bench) and [RL environments](/use-cases/rl-environments), where every episode should start from the same known state. The concept is explained in [what is a sandbox snapshot?](/glossary/sandbox-snapshot). Facts on this page were checked on 25 September 2026.