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.
Print output as it arrives
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
stdoutTruncatedistrue. Check the flag, add a callback, or write the output to a file (cmd > /workspace/out.log) and read it withsbx.files.readText. - Treating a timeout as an exception. The result returns
timedOut: true(timed_outin Python) with the output so far. To throwCommandErroron a non-zero exit instead, addcheck: 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
truncatedevent, and both truncation flags are set. Keep the loop reading, or write to a file. - Streaming a server.
execwaits 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.
Related
- Run a background process and follow its logs after you disconnect.
- Open an interactive terminal for colors and prompts.
- Run untrusted LLM code, where an agent reads output as it is produced.
- The full exec reference in JavaScript and Python.
Facts on this page were checked on 26 October 2026.