A sandbox created without timeoutSeconds never stops on a timer. The
server renews its time for you while it runs, using free usage or credit. It
keeps running until you stop it, it pauses after being idle, or your credit
runs out. An extension of such a sandbox returns immediately and changes
nothing, so code written for a platform with leases keeps working. Running
time is billed as it is used: $0.03125 an hour for a waiting 2 vCPU,
4 GiB sandbox, and $0.08 when fully busy
(pricing, checked 25 October 2026).
Extend a sandbox that has a time limit
TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.create({ timeoutSeconds: 600 }); // a ten-minute limitconsole.log("ends at", sbx.info.endsAt);await sbx.extend(1800); // 30 more minutesawait sbx.refresh();console.log("now ends at", sbx.info.endsAt);await sbx.stop();Pythonfrom withruntime import Sandboxsbx = Sandbox.create(timeout_seconds=600) # a ten-minute limitprint("ends at", sbx.info["endsAt"])sbx.extend(1800) # 30 more minutesprint("now ends at", sbx.refresh().info["endsAt"])sbx.stop()Terminalruntime sandboxes extend "${id}" 1800 # prints the new endOver HTTP, send POST /v1/sandboxes/{id}:extend with {"seconds": 600}.
An agent over MCP calls runtime_sandboxes_manage with "action": "extend".
endsAt is null on a sandbox that never stops by itself.
When the time has already run out
With the default onLeaseEnd: "pause", the sandbox pauses. It is not deleted.
Files, memory and running processes are kept. A job that ran past its time
can be woken and finished, rather than started again:
TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.connect(process.env.SANDBOX_ID!);if (sbx.state === "paused") await sbx.wake({ timeoutSeconds: 3600 });await sbx.exec("make test", { timeoutMs: 1_800_000 });Pythonimport osfrom withruntime import Sandboxsbx = Sandbox.connect(os.environ["SANDBOX_ID"])if sbx.state == "paused": sbx.wake(timeout_seconds=3600)sbx.exec("make test", timeout_ms=1_800_000)A request to a paused sandbox wakes it automatically. The sandbox gets a new
limit set by its own timeoutSeconds. A wake never shortens a limit. Time
that an extension added before the pause is kept.
Settings
| Setting | Default | Range or effect |
|---|---|---|
timeoutSeconds |
none | An optional limit, 60 to 86,400 (24 hours). Without it, the sandbox runs while busy |
extend(seconds) |
none | Moves a limit later, up to 24 hours ahead of now |
onLeaseEnd |
"pause" |
Or "stop", at a limit or when credit runs out |
wake({ timeoutSeconds }) |
its own timeout | A new limit on every wake, for a sandbox that has one |
idlePauseSeconds |
300 | Pauses it after this long with nothing happening. 0 never pauses |
persistent: true |
false | Paid only. Runs until you stop it, idle or not, while credit lasts |
The CLI takes --timeout <seconds> and --on-timeout pause|stop|delete on
runtime sandboxes create. Python uses timeout_seconds and on_lease_end.
Mistakes to avoid
- Setting a limit out of habit. A long job needs no limit and nothing to
keep it alive. Leave
timeoutSecondsout, and it runs while it works. - Confusing a time limit with a command's timeout.
timeoutMsonexecbounds one command (60 seconds by default, 24 hours at most). A time limit bounds the machine. - Extending past your daily limit. A key with a daily spending limit
refuses an extension past it with
spending_limit_reached(HTTP 402). The SDK does not retry it (security). - Choosing
"stop"for work you might resume. A stopped sandbox is not a backup. Keep"pause"unless the sandbox holds nothing you need.
Related
- Keep a sandbox running for servers and notebooks that run for hours.
- Pause when idle to stop paying while it waits.
- Pause and resume a sandbox by hand.
- Time and lifetime in the sandbox environment guide.
Facts on this page were checked on 25 October 2026.