# exec & execCode
URL: /docs/core/concepts/exec

Run shell commands with exec() and interpreted code with execCode().



## exec() [#exec]

`sb.exec(cmd, opts?)` runs a shell command inside the container and returns an `ExecHandle`.

```ts
// Await for full result
const { stdout, stderr, exitCode } = await sb.exec("node --version");

// Stream stdout in real time
await sb.exec("npm run build").pipe(process.stdout);

// Iterate chunks
for await (const chunk of sb.exec("npm test").stdout()) {
  process.stdout.write(chunk);
}
```

### Multi-line scripts [#multi-line-scripts]

Pass a multi-line string to run a bash script:

```ts
const script = `
#!/bin/bash
set -euo pipefail
echo "=== system info ==="
uname -a
echo "=== disk usage ==="
df -h /
`.trim();

await sb.exec(script).pipe(process.stdout);
```

### ExecOptions [#execoptions]

| Option      | Type                     | Default | Description                                                                         |
| ----------- | ------------------------ | ------- | ----------------------------------------------------------------------------------- |
| `strict`    | `boolean`                | `true`  | Throw `CommandError` on non-zero exit. Set to `false` to get the exit code instead. |
| `cwd`       | `string`                 | —       | Working directory inside the sandbox                                                |
| `env`       | `Record<string, string>` | —       | Extra environment variables for this exec only                                      |
| `timeoutMs` | `number`                 | —       | Abort the command after this many milliseconds                                      |

### Exec timeout [#exec-timeout]

Use `timeoutMs` to abort a command that runs too long:

```ts
try {
  await sb.exec("npm test", { timeoutMs: 30_000 }); // abort after 30s
} catch (e) {
  if (e instanceof CommandError) {
    console.error("timed out or failed:", e.exitCode);
  }
}
```

### Strict vs non-strict [#strict-vs-non-strict]

```ts
// strict (default) — throws CommandError on non-zero exit
try {
  await sb.exec("exit 42");
} catch (e) {
  if (e instanceof CommandError) {
    console.error(`exit ${e.exitCode}`); // 42
  }
}

// non-strict — returns exitCode in result
const { exitCode } = await sb.exec("test -f /etc/hostname", { strict: false });
if (exitCode === 0) {
  console.log("file exists");
}
```

### Using captured output in subsequent commands [#using-captured-output-in-subsequent-commands]

```ts
const { stdout: nodeVersion } = await sb.exec('node -e "process.stdout.write(process.version)"');

await sb.exec(`echo "Building with ${nodeVersion.trim()}"`).pipe(process.stdout);
```

Template literals with exec output work because the exec is already awaited — there's no ordering issue.

## execCode() [#execcode]

`sb.execCode(code, opts?)` runs code via the sandbox's code interpreter (Python, JS, TypeScript) using the execd `/code` endpoint. Requires a code-interpreter image.

```ts
import { CodeLanguage } from "@alineo-labs/sandbox";

const sb = await client.sandbox({
  image: "opensandbox/code-interpreter",
  resources: { cpu: "500m", memory: "512Mi" },
  // Required for this image — starts the Jupyter kernel service execCode() depends on.
  entrypoint: ["/opt/code-interpreter/code-interpreter.sh"],
});
```

### Stateless execution [#stateless-execution]

Each call without a context runs in an isolated interpreter session:

```ts
await sb
  .execCode(
    `
import sys, math
print(f"Python {sys.version.split()[0]}")
print(f"pi = {math.pi:.6f}")
`.trim(),
  )
  .pipe(process.stdout);
```

### Stateful execution [#stateful-execution]

Contexts must be created first via `createCodeContext()` — you can't hand-roll one. Pass the returned context to make variables persist across calls:

```ts
const ctx = await sb.createCodeContext(CodeLanguage.Python);

await sb.execCode(`data = [2**i for i in range(8)]`, { context: ctx });
await sb.execCode(`print(f"sum = {sum(data)}")`, { context: ctx }).pipe(process.stdout);
// sum = 255
```

### ExecCodeOptions [#execcodeoptions]

| Option    | Type                                     | Description                                                                            |
| --------- | ---------------------------------------- | -------------------------------------------------------------------------------------- |
| `context` | `{ id: string, language: CodeLanguage }` | Stateful interpreter session. Variables defined in one call are available in the next. |

### CodeLanguage [#codelanguage]

```ts
import { CodeLanguage } from "@alineo-labs/sandbox";

CodeLanguage.Python; // "python"
CodeLanguage.JavaScript; // "javascript"
CodeLanguage.TypeScript; // "typescript"
```

## proxy() [#proxy]

```ts
await sb.proxy(port: number): Promise<{ url: string; headers: Record<string, string> }>
```

Returns a proxied URL and auth headers for a port running inside the sandbox. Use this to send HTTP requests to a server started with `exec`.

```ts
await sb.exec("node server.js &");
// wait a moment for the server to be ready
await sb.exec("sleep 1");

const { url, headers } = await sb.proxy(3000);
const res = await fetch(`${url}/health`, { headers });
console.log(await res.text());
```

The returned `url` is routable from outside the sandbox. The `headers` contain the execd auth token required by OpenSandbox's proxy layer — pass them along with every request.

## metrics() [#metrics]

```ts
await sb.metrics(): Promise<{ cpu: number; memory: number; timestamp: string }>
```

Returns current CPU and memory usage for the sandbox container.

```ts
const { cpu, memory, timestamp } = await sb.metrics();
console.log(`CPU: ${cpu}, Memory: ${memory} at ${timestamp}`);
```

Useful for monitoring resource consumption during heavy workloads or detecting runaway processes before a timeout fires.
