Skip to main content
sbx.exec runs a command and waits for it. sbx.spawn starts a command and hands you a live handle. The sandbox must be running; otherwise both fail with invalid_state (409).

exec

A string runs under bash -lc, so pipes, && and globs work. An array runs as-is, with no shell:
A non-zero exit is a normal result, not an error. Pass check: true to throw a CommandError (with exitCode and stderr) instead.

Options

Buffered or streamed

exec picks one of two transports:
  • Buffered (POST /v1/sandboxes/{id}/exec) when none of the conditions below apply. The command runs for at most 55 s, and 30 s if you set no timeoutMs. Stdin is at most 1 MiB, the command string at most 16 KB, and output is cut at 1 MiB per stream (stdout_truncated / stderr_truncated say so).
  • Streamed over the attach WebSocket when you pass onStdout or onStderr, set tty, pass stdin as a Uint8Array or larger than 1 MiB, set timeoutMs above 55000, or set maxOutputBytes. There is no server-side time limit. timeoutMs is enforced by the SDK: it closes the session, which kills the process, and returns timed_out: true with exit_code -1. When you pass no stdin, the SDK closes stdin at once so commands that read it do not wait.
A bare exec("npm test") uses the buffered route, and the API kills it after 30 s: the result has timed_out: true and exit_code -1. For anything that may run longer, pass timeoutMs (up to 55000 stays buffered, more switches to the attach socket), pass an output callback, or use spawn.
On the streamed route, env travels in a request header, never in the URL.

Result

exec resolves with an ExecResult: For binary output, read a file with files.read or use the raw chunks from spawn.

spawn

sbx.spawn(command?, options?) opens the attach WebSocket and returns a CommandHandle at once. A string runs under bash -lc, an array runs as-is, and no command opens a login shell. It takes the same options as exec except check.

CommandHandle

Writes made before the socket opens are queued. If you pass stdin in the options, it is written and stdin is closed for you; otherwise stdin stays open until you call closeStdin(). wait() and ready() reject with a ZodeError when the session fails: attach_failed (the socket could not open), attach_closed (it closed without an exit status, which is what kill() with no signal causes), or session_error (the sandbox ended the session with an error).

Interactive shell

Closing the session kills the process. A process you start through exec or spawn lives only as long as its session.