# Sandboxes
URL: /docs/core/concepts/sandboxes

Isolated Docker containers managed by OpenSandbox — how they're created, configured, and closed.



A sandbox is a Docker container managed by OpenSandbox. `client.sandbox()` creates one and returns a live `SandboxHandle` object. The container persists until `sb.close()` is called.

## Creating a sandbox [#creating-a-sandbox]

```ts
const sb = await client.sandbox({
  image: "ubuntu:22.04",
  resources: { cpu: "500m", memory: "512Mi" },
  name: "my-sandbox",
});
```

`client.sandbox()` does three things:

1. Calls the OpenSandbox control API to create the container
2. Waits until the container reaches `Running` state
3. Returns the `SandboxHandle` object

## SandboxOptions [#sandboxoptions]

| Option            | Type                                            | Description                                                                                                                                                        |
| ----------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `image`           | `string \| { uri, auth? }`                      | Container image. String form: `"ubuntu:22.04"`. Object form for private registries: `{ uri: "ghcr.io/org/image", auth: { username, password } }`                   |
| `resources`       | `{ cpu: string; memory: string; gpu?: string }` | Resource limits. Required. `cpu` is a Kubernetes-style string like `"500m"` or `"2"`. `memory` is `"256Mi"`, `"1Gi"`, etc.                                         |
| `env`             | `Record<string, string>`                        | Environment variables set in the container at startup                                                                                                              |
| `metadata`        | `Record<string, string>`                        | Arbitrary key-value labels attached to the sandbox (e.g. `{ runId: "ci-42" }`)                                                                                     |
| `name`            | `string`                                        | User-provided name for the run — used as the ledger key. Auto-generated if omitted.                                                                                |
| `timeout`         | `number`                                        | Sandbox lifetime in seconds. Defaults to the OpenSandbox server's default.                                                                                         |
| `hooks`           | `SandboxHooks`                                  | Lifecycle callbacks for observability. See [Observability](/docs/core/observability).                                                                              |
| `networkPolicy`   | `{ defaultAction, egress }`                     | Optional outbound network policy — which hosts the sandbox may reach. Required to use `credentialProxy`. See [Network policy](/docs/core/concepts/network-policy). |
| `credentialProxy` | `boolean`                                       | Opt-in to credential injection via `sb.credentials.*`. See [Credentials](/docs/core/concepts/credentials).                                                         |

## Sandbox lifecycle [#sandbox-lifecycle]

Always use `try/finally` to ensure the container is deleted even if a step throws:

```ts
const sb = await client.sandbox({
  image: "ubuntu:22.04",
  resources: { cpu: "500m", memory: "256Mi" },
});

try {
  await sb.exec("npm ci");
  await sb.exec("npm test").pipe(process.stdout);
} finally {
  await sb.close(); // deletes the container, writes sandbox_closed to ledger
}
```

`close()` is idempotent — subsequent calls are no-ops.

## SandboxHandle properties [#sandboxhandle-properties]

```ts
sb.sandboxId; // OpenSandbox container ID — also the unique ledger key
sb.name; // User-provided name, or "sandbox-<short-id>" if omitted
```

## Multiple sandboxes [#multiple-sandboxes]

Each `client.sandbox()` call creates an independent container. Hold them as separate variables:

```ts
const sbA = await client.sandbox({ image: "node:22", resources: { cpu: "500m", memory: "512Mi" } });
const sbB = await client.sandbox({
  image: "python:3.11",
  resources: { cpu: "500m", memory: "512Mi" },
});

try {
  await sbA.exec("node --version").pipe(process.stdout);
  await sbB.exec("python3 --version").pipe(process.stdout);
} finally {
  await sbA.close();
  await sbB.close();
}
```

## Concurrency limits [#concurrency-limits]

`SandboxClientOptions.maxConcurrency` caps how many sandboxes may be active at once. When at capacity, `client.sandbox()` awaits until a slot is free (released by `sb.close()`):

```ts
const client = new Sandbox({
  baseUrl: "http://localhost:8080",
  adapter: new SQLiteAdapter("./alineo.db"),
  maxConcurrency: 5, // at most 5 active sandboxes
});
```
