Terminal connections
Terminal connections let browser-based UIs interact directly with sandbox shells. Instead of executing discrete commands with exec(), a terminal connection opens a persistent, bidirectional channel to a bash shell — the same model as SSH or a local terminal emulator.
Terminal connections use WebSockets to stream raw bytes between a browser terminal (like xterm.js ↗) and a pseudo-terminal (PTY) process running inside the sandbox container.
Browser (xterm.js) <-- WebSocket --> Worker <-- proxy --> Container PTY (bash)- The browser sends a WebSocket upgrade request to your Worker
- Your Worker calls
sandbox.terminal(request), which proxies the upgrade to the container - The container spawns a bash shell attached to a PTY
- Raw bytes flow bidirectionally — keystrokes in, terminal output out
This is fundamentally different from exec():
exec()runs a single command to completion and returns the resultterminal()opens a persistent shell where users type commands interactively
The container buffers terminal output in a ring buffer. When a client disconnects and reconnects, the server replays buffered output so the terminal appears unchanged. This means:
- Short network interruptions are invisible to users
- Reconnected terminals show previous output without re-running commands
- The buffer has a fixed size, so very old output may be lost
No client-side code is needed to handle buffering — the container manages it transparently.
Network interruptions are common in browser-based applications. Terminal connections handle this through a combination of server-side buffering (described above) and client-side reconnection with exponential backoff.
The SandboxAddon for xterm.js implements this automatically. If you are building a custom client, you are responsible for your own reconnection logic — the server-side buffering works regardless of which client connects. Refer to the WebSocket protocol reference for details on the connection lifecycle.
Each session can have its own terminal with independent shell state:
const devSession = await sandbox.createSession({ id: "dev", cwd: "/workspace/frontend", env: { NODE_ENV: "development" },});
const testSession = await sandbox.createSession({ id: "test", cwd: "/workspace", env: { NODE_ENV: "test" },});
// Each session's terminal has its own working directory,// environment variables, and command historyMultiple browser clients can connect to the same session's terminal simultaneously — they all see the same shell output and can all send input. This enables collaborative terminal use cases.
Terminal connections use binary WebSocket frames for terminal I/O (for performance) and JSON text frames for control and status messages (for structure). This keeps the data path fast while still allowing structured communication for operations like terminal resizing.
For the full protocol specification, including the connection lifecycle and message formats, refer to the Terminal API reference.
| Use case | Approach |
|---|---|
| Run a command and get the result | exec() or execStream() |
| Interactive shell for end users | terminal() |
| Long-running process with real-time output | startProcess() + streamProcessLogs() |
| Collaborative terminal sharing | terminal() with shared session |
- Terminal API reference — Method signatures and types
- Browser terminals — Step-by-step setup guide
- Session management — How sessions work
- Architecture — Overall SDK design