> ## Documentation Index
> Fetch the complete documentation index at: https://docs.simplesandbox.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Command Execution

> Execute commands and run background processes in sandboxes

## Overview

Execute shell commands inside sandboxes using the `exec()` method. Commands run via `/bin/sh -c`, supporting pipes, variables, and shell features.

## Prerequisites

Before executing commands, ensure you have:

* Installed the Sandbox SDK ([see Quickstart](/quickstart))
* Created a sandbox instance
* Basic familiarity with shell commands and async/await in JavaScript/TypeScript

## Basic execution

```typescript theme={null}
// Simple command
const result = await sandbox.exec("echo 'Hello World'");
console.log(result.stdout);    // "Hello World\n"
console.log(result.exitCode);  // 0
console.log(result.success);   // true
```

## Shell features

Commands support full shell syntax:

```typescript theme={null}
// Pipes and redirection
await sandbox.exec("cat file.txt | grep error > errors.log");

// Multiple commands
await sandbox.exec("npm install && npm test");

// Variables and globs
await sandbox.exec("for f in *.txt; do echo $f; done");
```

## Options

### Timeout

Set a maximum execution time (max 60 seconds):

```typescript theme={null}
const result = await sandbox.exec("npm install", {
  timeoutMs: 30_000  // 30 seconds
});
```

<Note>
  Max per-command timeout is 60 seconds. For long-running servers, use <code>background: true</code> and redirect output to a log file (for example, <code>>/tmp/server.log 2>&1</code>).
</Note>

### Environment variables

Pass environment variables to individual commands using the `env` option:

```typescript theme={null}
// Single environment variable
const result = await sandbox.exec("echo $MY_VAR", {
  env: { MY_VAR: "hello world" }
});

// Multiple environment variables
await sandbox.exec("node app.js", {
  env: {
    NODE_ENV: "production",
    PORT: "3000",
    API_KEY: "secret-key-12345",
    DEBUG: "true"
  }
});

// Use in shell commands
await sandbox.exec("echo Database: $DB_URL", {
  env: { DB_URL: "postgresql://localhost:5432/mydb" }
});
```

Environment variables are merged with the sandbox's existing environment, with your custom values taking precedence:

```typescript theme={null}
// Start a Node.js server with environment configuration
await sandbox.exec("node server.js >/tmp/server.log 2>&1", {
  background: true,
  env: {
    NODE_ENV: "production",
    PORT: "8080",
    DATABASE_URL: "postgres://user:pass@db:5432/app"
  }
});

// Run Python script with custom environment
await sandbox.exec("python app.py", {
  env: {
    PYTHONPATH: "/app/lib",
    FLASK_ENV: "development",
    SECRET_KEY: "my-secret-key"
  }
});
```

<Note>
  Environment variables are only set for the specific command execution. To persist environment variables across multiple commands, either:

  * Pass the same <code>env</code> object to each <code>exec()</code> call
  * Use shell export syntax: <code>export VAR=value && command</code>
  * Write them to a file and source it: <code>source /tmp/env.sh && command</code>
</Note>

### Working directory

Set a persistent working directory for commands:

```typescript theme={null}
sandbox.cwd("/app/project");

// Subsequent commands run in /app/project
await sandbox.exec("bun install");
await sandbox.exec("bun test");

// Override for a single command
await sandbox.exec("ls", { cwd: "/tmp" });

// Get current directory
console.log(sandbox.getCwd());  // "/app/project"
```

Working directory persists across commands and affects `exec()` and file operations.

### Standard input

Pass data to stdin:

```typescript theme={null}
await sandbox.exec("cat > /tmp/input.txt", {
  stdin: "line 1\nline 2\nline 3\n"
});

// Or pipe data
await sandbox.exec("python process.py", {
  stdin: JSON.stringify({ data: [1, 2, 3] })
});
```

## Background processes

Run long-lived processes without blocking:

```typescript theme={null}
// Start server in background
await sandbox.exec("python server.py >/tmp/server.log 2>&1", {
  background: true
});

// Command returns immediately
// Server continues running
```

### Real-time output streaming

Stream command output with callbacks:

```typescript theme={null}
await sandbox.exec("npm install && npm test", {
  onStdout: (line) => console.log(line),
  onStderr: (line) => console.error(line)
});

// Stream logs from background process
await sandbox.exec("python server.py 2>&1", {
  background: true,
  onStdout: (line) => {
    if (line.includes("ERROR")) {
      console.error("Server error:", line);
    }
  }
});
```

Callbacks receive output line-by-line as commands execute.

### Managing background processes

Check if a process is running:

```typescript theme={null}
// Find PID
const pid = await sandbox.exec("pgrep -f server.py || echo 'not running'");
console.log("PID:", pid.stdout.trim());

// Check with ps
const ps = await sandbox.exec("ps aux | grep server.py | grep -v grep");
console.log(ps.stdout);
```

Read logs from background processes:

```typescript theme={null}
// Tail recent logs
const tail = await sandbox.exec("tail -n 100 /tmp/server.log");
console.log(tail.stdout);

// Follow logs (with timeout)
const follow = await sandbox.exec("timeout 5 tail -f /tmp/server.log", {
  timeoutMs: 6_000
});
```

Stop a background process:

```typescript theme={null}
// Kill by name
await sandbox.exec("pkill -f server.py");

// Kill by PID
await sandbox.exec("kill 1234");

// Force kill
await sandbox.exec("pkill -9 -f server.py");
```

## Error handling

```typescript theme={null}
const result = await sandbox.exec("ls /nonexistent");

if (!result.success) {
  console.error("Command failed:");
  console.error("Exit code:", result.exitCode);
  console.error("Error output:", result.stderr);
}
```

## Common patterns

### Install dependencies and run

```typescript theme={null}
await sandbox.exec("npm install", { timeoutMs: 60_000 });
await sandbox.exec("npm test", {
  timeoutMs: 30_000,
  env: { NODE_ENV: "test", CI: "true" }
});
```

### Start server and wait for readiness

```typescript theme={null}
// Start server
await sandbox.exec("node server.js >/tmp/server.log 2>&1", {
  background: true
});

// Wait for port to be ready
for (let i = 0; i < 10; i++) {
  const check = await sandbox.exec("nc -z localhost 3000 && echo ready || echo waiting");
  if (check.stdout.includes("ready")) {
    break;
  }
  await new Promise(r => setTimeout(r, 1000));
}

const host = sandbox.expose(3000);
console.log(`Server ready at https://${host}`);
```

### Capture output to file

```typescript theme={null}
// Run and capture both stdout and stderr
await sandbox.exec("python script.py > /tmp/output.log 2>&1");

// Read the output
const output = await sandbox.files.read("/tmp/output.log");
console.log(output);
```

### Capture stderr for debugging

To capture error messages when commands fail silently, redirect stderr:

```typescript theme={null}
// Redirect stderr to stdout and capture to file
await sandbox.exec("python script.py 2>&1 | tee /tmp/output.log");

// Read captured output
const logs = await sandbox.files.read("/tmp/output.log");
console.log(logs);
```

### Conditional execution

```typescript theme={null}
// Run only if file exists
await sandbox.exec("test -f /app/config.json && node app.js || echo 'Config missing'");

// Chain with error handling
await sandbox.exec("npm test || (echo 'Tests failed' && exit 1)");
```

### Using environment variables with background processes

Combine `env` with `background` for configurable long-running services:

```typescript theme={null}
// Start a web server with custom configuration
await sandbox.exec("node server.js >/tmp/server.log 2>&1", {
  background: true,
  env: {
    NODE_ENV: "production",
    PORT: "3000",
    API_KEY: process.env.MY_API_KEY, // Pass through from your environment
    DATABASE_URL: "postgresql://localhost/mydb",
    LOG_LEVEL: "info"
  }
});

// Give the server time to start
await new Promise(r => setTimeout(r, 2000));

// Expose the port
const host = sandbox.expose(3000);
console.log(`Server running at https://${host}`);

// Check server logs if needed
const logs = await sandbox.exec("tail -n 50 /tmp/server.log");
console.log(logs.stdout);
```

## Best practices

* **Set timeouts**: Always specify `timeoutMs` for potentially long operations
* **Use env option**: Prefer the `env` option over inline `export` commands for cleaner, more maintainable code
* **Redirect output**: For background processes, redirect to log files (`>/tmp/log 2>&1`)
* **Check success**: Always check `result.success` before assuming command worked
* **Use background for servers**: Don't block on long-running processes
* **Clean up processes**: Kill background processes before terminating sandbox
* **Escape carefully**: Be mindful of shell escaping when passing user input
* **Secure secrets**: Use the `env` option to pass sensitive data instead of embedding it in command strings

## Limitations

* Max timeout per command: 60 seconds
* Background processes continue until sandbox stops or you kill them
* No interactive TTY support
* Commands run as root inside the container
