How to run a background process in a sandbox
Call spawn() with the command; it starts a server, watcher or REPL, returns at once, and keeps running after you disconnect.
On Runtime a background process outlives the connection that started it, and a paused sandbox keeps it running across the pause. Reconnect from another process and get it back by id, with its output from the start. A sandbox whose server sits waiting costs $0.03125 an hour at 2 vCPU and 4 GiB, and $0.08 an hour with both CPUs busy (pricing, checked 25 September 2026).
Start a server and a REPL
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create();const server = await sbx.spawn("python3 -m http.server 8000", { cwd: "/workspace" });console.log(server.id, server.info.state);const repl = await sbx.spawn(["python3", "-i", "-q"], { stdin: "pipe" });await repl.write("print(21 * 2)\n");await repl.write("exit()\n", { eof: true });console.log((await repl.wait()).stdout);for (const p of await sbx.processes.list()) console.log(p.id, p.state, p.command);await server.kill("SIGTERM");Pythonfrom withruntime import Sandboxwith Sandbox.create() as sbx: server = sbx.spawn("python3 -m http.server 8000", cwd="/workspace") print(server.id, server.info["state"]) repl = sbx.spawn(["python3", "-i", "-q"], stdin="pipe") repl.write("print(21 * 2)\n") repl.write("exit()\n", eof=True) print(repl.wait().stdout) for process in sbx.processes(): print(process["id"], process["state"], process["command"]) server.kill("SIGTERM")A string runs under bash -c; a list runs the program with no shell.
stdin: "pipe" keeps the process's input open so write() can feed it, and
eof closes it.
From the command line
spawn prints the process id, ps lists processes, and logs prints what one
has written so far and returns, even while it runs:
Terminalid=$(runtime sandbox create)pid=$(runtime sandbox spawn "${id}" -- python3 -m http.server 8000)runtime sandbox ps "${id}"runtime sandbox logs "${id}" "${pid}"runtime sandbox kill "${id}" "${pid}"runtime sandbox stop "${id}"Terminalruntime sandbox logs "${id}" "${pid}" -f # follow until the process exitsAn agent over MCP calls runtime_sandbox_exec with "background": true, then
runtime_sandbox_process with "action": "read" to follow its output
(MCP).
Get a process back later
A process does not belong to the script that started it. Save its id, and any later process reconnects and reads from wherever it left off:
TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.connect(process.env.SANDBOX_ID!);const job = await sbx.processes.get(process.env.PROCESS_ID!);for await (const event of job.output({ cursor: 0 })) { if (event.type === "stdout") process.stdout.write(event.data); if (event.type === "exit") console.log("exit", event.exitCode);}Pythonimport osfrom withruntime import Sandboxsbx = Sandbox.connect(os.environ["SANDBOX_ID"])job = sbx.process(os.environ["PROCESS_ID"])for event in job.output(cursor=0): if event["type"] == "stdout": print(event["data"], end="")output() yields every event from the start, or from a cursor, until the
process exits.
What a process gets
| Setting or limit | Value |
|---|---|
| Returns | At once, with the process id and its state |
| Input | stdin: "pipe" (Python stdin="pipe") for write(); eof closes it |
| Signals | kill("SIGTERM") or any signal name; POST …/processes/{id}:signal |
| Output kept | The latest 1 MiB of each process's output, in the sandbox |
| Across a pause | Running processes are kept with memory and carry on after the wake |
| Lifetime | Until it exits, is killed, or the sandbox stops |
| Terminal | Add pty: { cols, rows } for a program that needs one |
| Cost | No charge per process; the sandbox's measured CPU and reserved memory |
Mistakes to avoid
- Starting a server with
exec. A process started byexecends with its command, andexecwaits for it. A server, a file watcher or a queue worker goes inspawn. - Printing more than 1 MiB and reading it later. A reader that was away
while more than that came out gets a
truncatedevent saying how many bytes are gone, andwait()sets both truncation flags. Send a chatty process's output to a file and read the file. - Forgetting the lease. A sandbox runs until its lease ends, then pauses by default, and its processes pause with it. For a server that must answer all day, see keep a sandbox running.
- Opening a port with nothing listening. Check
processes.list()shows the server as running before you share its port with a preview orruntime sandbox port-forward.
Related
- Stream command output for commands that end.
- Open an interactive terminal for a shell you type into.
- Preview agent-built apps: a spawned dev server, shared at an HTTPS address.
- Background processes in the SDK reference.
Facts on this page were checked on 25 September 2026.