Skip to content
Runtime

How to run a background process in a sandbox

Call spawn() with the command. It starts a server, watcher or REPL, returns immediately, and keeps running after you disconnect.

On Runtime, a background process outlives the connection that started it. A paused sandbox keeps the process running across the pause. Reconnect from another process, and get the process back by its ID, with its output from the start. A sandbox whose server sits waiting costs $0.03125 an hour at 2 vCPU and 4 GiB. With both CPUs busy, it costs $0.08 an hour (pricing, checked 26 October 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. logs prints what a process has written so far, then returns, even while the process runs:

Terminalid=$(runtime sandboxes create)pid=$(runtime sandboxes spawn "${id}" -- python3 -m http.server 8000)runtime sandboxes ps "${id}"runtime sandboxes logs "${id}" "${pid}"runtime sandboxes kill "${id}" "${pid}"runtime sandboxes stop "${id}"
Terminalruntime sandboxes logs "${id}" "${pid}" -f   # follow until the process exits

An agent over MCP calls runtime_sandboxes_exec with "background": true. Then it calls runtime_sandboxes_process with "action": "read" to follow the output (MCP).

Get a process back later

A process does not belong to the script that started it. Save its ID. Any later process can reconnect and read the output from where 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 Immediately, 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 their memory, and continue 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 by exec ends when its command ends, and exec waits for it. Start a server, a file watcher or a queue worker with spawn.
  • Printing more than 1 MiB and reading it later. A reader that was away while more than that came out gets a truncated event. The event says how many bytes are gone. wait() sets both truncation flags. For a process with a lot of output, send the output to a file and read the file.
  • Expecting it to run with nothing happening. A running process keeps its sandbox running, with no time limit. But a server that waits with no request, traffic or CPU use is idle. The sandbox pauses itself after idlePauseSeconds, and a request wakes it. For a server that must respond all day without a wake, see keep a sandbox running.
  • Opening a port with nothing listening. Before you share a port with a preview or runtime sandboxes port-forward, check that processes.list() shows the server as running.

Facts on this page were checked on 26 October 2026.

100 free hoursin your first 30 days.

of a 1 GB machine

  • No credit card
  • Four sandboxes at once, 2 vCPU and 4 GiB each
  • Then prepaid credit from $10, no plan fee
Start free, no card
Start free, no card