Skip to content
Runtime

How to stream command output from a sandbox

Pass onStdout to exec (on_stdout in Python), or loop over execStream(). Each chunk arrives as the command prints it.

On Runtime, a streamed command has no output limit. A long stream resumes automatically from the correct byte. When a stream runs past the server's time limit, the SDK resumes it from a cursor. No line is lost or printed twice. The first line of a build or a test run reaches your terminal almost immediately.

Callbacks receive each piece of stdout and stderr as text. The result still holds everything the command printed:

TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create();const result = await sbx.exec("for i in 1 2 3; do echo line $i; sleep 1; done", {  onStdout: (text) => process.stdout.write(text),  onStderr: (text) => process.stderr.write(text),});console.log("exit", result.exitCode, result.stdoutTruncated);
Pythonimport sysfrom withruntime import Sandboxwith Sandbox.create() as sbx:    result = sbx.exec("for i in 1 2 3; do echo line $i; sleep 1; done",                      on_stdout=sys.stdout.write, on_stderr=sys.stderr.write)    print("exit", result.exit_code, result.stdout_truncated)

From a terminal, runtime sandboxes exec streams output by default. It exits with the command's own exit code, or with 124 when the command times out. Scripts that use set -e behave as expected:

Terminalid=$(runtime sandboxes create)runtime sandboxes exec "${id}" -- python3 -c 'print(sum([125, 250, 375]))'runtime sandboxes stop "${id}"

Read the events one by one

To tell the streams apart or act on the exit, iterate over the events. Each event has a type: start, stdout, stderr or exit.

TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create();for await (const event of sbx.execStream("npm --version")) {  if (event.type === "stdout") process.stdout.write(event.data);  if (event.type === "stderr") process.stderr.write(event.data);  if (event.type === "exit") console.log("exit", event.exitCode);}
Pythonfrom withruntime import Sandboxwith Sandbox.create() as sbx:    for event in sbx.exec_stream("npm --version"):        if event["type"] == "stdout":            print(event["data"], end="")        elif event["type"] == "exit":            print("exit", event["exitCode"])

Over plain HTTP, POST /v1/sandboxes/{id}:exec with "stream": true returns NDJSON, with one event per line. A continue event carries the cursor to resume from (commands and processes).

Output limits

Case What you get back
exec with no callback, timeout up to 60s At most 64 KiB of stdout and 64 KiB of stderr in the result
exec with onStdout or onStderr Streams; the result keeps everything the command printed
exec with timeoutMs over 60,000 Streams by itself, as if you passed a callback
execStream() Every event, with no output limit
A reader far behind The sandbox keeps the latest 1 MiB; a truncated event says so
Timeout 60 s by default, up to 24 h when streamed. A timeout returns a result, not an error
runtime sandboxes exec --json One result, at most 64 KiB of each stream, with the truncation flags

Output has no charge of its own. The sandbox is billed for the CPU it uses, at $0.025 per active vCPU-hour, and for its memory, at $0.0075 per GiB-hour (pricing).

Mistakes to avoid

  • Reading a big log from the plain result. Past 64 KiB, the rest is dropped and stdoutTruncated is true. Check the flag, add a callback, or write the output to a file (cmd > /workspace/out.log) and read it with sbx.files.readText.
  • Treating a timeout as an exception. The result returns timedOut: true (timed_out in Python) with the output so far. To throw CommandError on a non-zero exit instead, add check: true.
  • A reader that stops reading. A slow reader is fine. The command waits for it. The sandbox holds the latest 1 MiB of a command's output. If a consumer is away for more than 10 seconds while more output arrives, it loses the oldest part. It then gets a truncated event, and both truncation flags are set. Keep the loop reading, or write to a file.
  • Streaming a server. exec waits for the command to end. A dev server or a watcher belongs in a background process. Follow its output separately.
  • A secret in the command line. Pass it in env. It is never echoed back, and journals record a hash, not the value.

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