Skip to main content

Documentation Index

Fetch the complete documentation index at: https://e2b-squash-sandbox-pages.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

E2B sandboxes provide multiple ways to run commands and interact with the terminal: commands.run() for executing commands, the PTY module for interactive terminal sessions, and SSH access for remote connectivity.

Running commands

Use commands.run() to execute terminal commands inside the sandbox.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()
const result = await sandbox.commands.run('ls -l')
console.log(result)

Streaming output

To stream command output as it is being executed, pass onStdout/onStderr callbacks (JavaScript) or on_stdout/on_stderr callbacks (Python).
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

const result = await sandbox.commands.run('echo hello; sleep 1; echo world', {
  onStdout: (data) => {
    console.log(data)
  },
  onStderr: (data) => {
    console.log(data)
  },
})
console.log(result)

Running commands in background

To run commands in background, pass the background option. This returns immediately and the command continues running in the sandbox. You can later kill the command using commands.kill().
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

// Start the command in the background
const command = await sandbox.commands.run('echo hello; sleep 10; echo world', {
  background: true,
  onStdout: (data) => {
    console.log(data)
  },
})

// Kill the command
await command.kill()

Listing running processes

Use commands.list() to get all running processes in the sandbox, including background commands and PTY sessions.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

// Start a background process
const cmd = await sandbox.commands.run('sleep 300', { background: true })

// List all running processes
const processes = await sandbox.commands.list()
for (const proc of processes) {
  console.log(`PID: ${proc.pid}, Command: ${proc.cmd}`)
}

// Kill a process by PID
await sandbox.commands.kill(processes[0].pid)
Background commands started with commands.run() appear as /bin/bash in the cmd field, not the inner command string. Only currently running processes are returned — exited or killed processes are not included.

Interactive terminal (PTY)

The PTY (pseudo-terminal) module allows you to create interactive terminal sessions in the sandbox with real-time, bidirectional communication. Unlike commands.run() which executes a command and returns output after completion, PTY provides:
  • Real-time streaming - Output is streamed as it happens via callbacks
  • Bidirectional input - Send input while the terminal is running
  • Interactive shell - Full terminal support with ANSI colors and escape sequences
  • Session persistence - Disconnect and reconnect to running sessions

Create a PTY session

Use sandbox.pty.create() to start an interactive bash shell.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

const terminal = await sandbox.pty.create({
  cols: 80,              // Terminal width in characters
  rows: 24,              // Terminal height in characters
  onData: (data) => {
    // Called whenever terminal outputs data
    process.stdout.write(data)
  },
  envs: { MY_VAR: 'hello' },  // Optional environment variables
  cwd: '/home/user',          // Optional working directory
  user: 'root',               // Optional user to run as
})

// terminal.pid contains the process ID
console.log('Terminal PID:', terminal.pid)
The PTY runs an interactive bash shell with TERM=xterm-256color, which supports ANSI colors and escape sequences.

Timeout

PTY sessions have a configurable timeout that controls the session duration. The default is 60 seconds. For interactive or long-running sessions, set timeoutMs: 0 (JavaScript) or timeout=0 (Python) to keep the session open indefinitely.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

const terminal = await sandbox.pty.create({
  cols: 80,
  rows: 24,
  onData: (data) => process.stdout.write(data),
  timeoutMs: 0,  // Keep the session open indefinitely
})

Send input to PTY

Use sendInput() in JavaScript or send_stdin() in Python to send data to the terminal. These methods return a Promise (JavaScript) or complete synchronously (Python) - the actual output will be delivered to your onData callback.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

const terminal = await sandbox.pty.create({
  cols: 80,
  rows: 24,
  onData: (data) => process.stdout.write(data),
})

// Send a command (don't forget the newline!)
await sandbox.pty.sendInput(
  terminal.pid,
  new TextEncoder().encode('echo "Hello from PTY"\n')
)

Resize the terminal

When the user’s terminal window changes size, notify the PTY with resize(). The cols and rows parameters are measured in characters, not pixels.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

const terminal = await sandbox.pty.create({
  cols: 80,
  rows: 24,
  onData: (data) => process.stdout.write(data),
})

// Resize to new dimensions (in characters)
await sandbox.pty.resize(terminal.pid, {
  cols: 120,
  rows: 40,
})

Disconnect and reconnect

You can disconnect from a PTY session while keeping it running, then reconnect later with a new data handler. This is useful for resuming terminal sessions after network interruptions, sharing terminal access between multiple clients, or implementing terminal session persistence.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

// Create a PTY session
const terminal = await sandbox.pty.create({
  cols: 80,
  rows: 24,
  onData: (data) => console.log('Handler 1:', new TextDecoder().decode(data)),
})

const pid = terminal.pid

// Send a command
await sandbox.pty.sendInput(pid, new TextEncoder().encode('echo hello\n'))

// Disconnect - PTY keeps running in the background
await terminal.disconnect()

// Later: reconnect with a new data handler
const reconnected = await sandbox.pty.connect(pid, {
  onData: (data) => console.log('Handler 2:', new TextDecoder().decode(data)),
})

// Continue using the session
await sandbox.pty.sendInput(pid, new TextEncoder().encode('echo world\n'))

// Wait for the terminal to exit
await reconnected.wait()

Kill the PTY

Terminate the PTY session with kill().
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

const terminal = await sandbox.pty.create({
  cols: 80,
  rows: 24,
  onData: (data) => process.stdout.write(data),
})

// Kill the PTY
const killed = await sandbox.pty.kill(terminal.pid)
console.log('Killed:', killed)  // true if successful

// Or use the handle method
// await terminal.kill()

Wait for PTY to exit

Use wait() to wait for the terminal session to end (e.g., when the user types exit).
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()

const terminal = await sandbox.pty.create({
  cols: 80,
  rows: 24,
  onData: (data) => process.stdout.write(data),
})

// Send exit command
await sandbox.pty.sendInput(terminal.pid, new TextEncoder().encode('exit\n'))

// Wait for the terminal to exit
const result = await terminal.wait()
console.log('Exit code:', result.exitCode)

Interactive terminal (SSH-like)

Building a fully interactive terminal (like SSH) requires handling raw mode, stdin forwarding, and terminal resize events. For a production implementation, see the E2B CLI source code which uses the same sandbox.pty API documented above.

SSH access

SSH access enables remote terminal sessions, SCP/SFTP file transfers, and integration with tools that expect SSH connectivity.

Quickstart

1

Build the SSH template

Define a template with OpenSSH server and websocat:
// template.ts
import { Template, waitForPort } from 'e2b'

export const template = Template()
  .fromUbuntuImage('25.04')
  .aptInstall(['openssh-server'])
  .runCmd([
    'curl -fsSL -o /usr/local/bin/websocat https://github.com/vi/websocat/releases/latest/download/websocat.x86_64-unknown-linux-musl',
    'chmod a+x /usr/local/bin/websocat',
  ], { user: 'root' })
  .setStartCmd('sudo websocat -b --exit-on-eof ws-l:0.0.0.0:8081 tcp:127.0.0.1:22', waitForPort(8081))
Build the template:
// build.ts
import { Template, defaultBuildLogger } from 'e2b'
import { template as sshTemplate } from './template'

await Template.build(sshTemplate, 'ssh-ready', {
  cpuCount: 2,
  memoryMB: 2048,
  onBuildLogs: defaultBuildLogger(),
})
2

Create a sandbox from the template

import { Sandbox } from 'e2b'

const sbx = await Sandbox.create('ssh-ready')
console.log(sbx.sandboxId)
3

Connect from your machine

# Install websocat
brew install websocat

# Connect to your sandbox
ssh -o 'ProxyCommand=websocat --binary -B 65536 - wss://8081-%h.e2b.app' user@<sandbox-id>

How it works

This method uses websocat to proxy SSH connections over WebSocket through the sandbox’s exposed ports.
┌───────────────────────────────────────────────────────────┐
│  Your Machine                                             │
│  ┌──────────┐    ProxyCommand    ┌──────────────────┐     │
│  │   SSH    │ ────────────────── │    websocat      │     │
│  │  Client  │                    │   (WebSocket)    │     │
│  └──────────┘                    └─────────┬────────┘     │
└────────────────────────────────────────────┼──────────────┘

                         wss://8081-<sandbox-id>.e2b.app

┌────────────────────────────────────────────┼──────────────┐
│  E2B Sandbox                               ▼              │
│                                  ┌──────────────────┐     │
│                                  │    websocat      │     │
│                                  │  (WS → TCP:22)   │     │
│                                  └─────────┬────────┘     │
│                                            │              │
│                                  ┌─────────▼────────┐     │
│                                  │   SSH Server     │     │
│                                  │   (OpenSSH)      │     │
│                                  └──────────────────┘     │
└───────────────────────────────────────────────────────────┘