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

# TypeScript Sandbox SDK quickstart

> Create and manage Porter Sandboxes from TypeScript

The TypeScript Sandbox SDK is published as `porter-sandbox`. Use it from application code running in your sandbox-enabled Porter cluster.

<Warning>
  Sandboxes are in a private beta. Please reach out to us at [support@porter.run](mailto:support@porter.run) or over Slack if you are interested in joining.
</Warning>

## Install

Add the SDK to your application:

```bash theme={null}
npm install porter-sandbox
```

## Create your first sandbox

Create a sandbox, execute a command, print the command output, and terminate the sandbox when the work is done:

```typescript theme={null}
import { Porter } from "porter-sandbox";

const porter = new Porter();

const sandbox = await porter.sandboxes.create({
  image: "python:3.12-slim",
  name: "typescript-quickstart",
  tags: { example: "typescript-quickstart" },
});

try {
  const result = await sandbox.exec(["python", "-c", "print('hello from porter')"]);
  console.log(result.stdout);
} finally {
  await sandbox.terminate();
  porter.close();
}
```

The SDK connects to the in-cluster Sandbox API automatically when this code runs as a Porter Application in the same cluster where sandboxes are enabled.

If you need to invoke sandboxes from outside that cluster, set `PORTER_SANDBOX_API_KEY` to a Porter API token and `PORTER_CLUSTER_ID` to the target cluster. The SDK reads the project from the token and builds the external Porter API URL automatically; see [calling from outside the cluster](/sandboxes/getting-started#calling-from-outside-the-cluster) for details.

Use sandbox names when you need to fetch, inspect, exec into, or terminate a sandbox later. Sandbox names must be unique within a cluster and currently cannot be reused, even after the sandbox is terminated.

## Fetch logs

Logs are returned as structured log lines:

```typescript theme={null}
import { Porter } from "porter-sandbox";

const porter = new Porter();
const sandbox = await porter.sandboxes.create({
  image: "python:3.12-slim",
  name: "typescript-logs-demo",
});

try {
  await sandbox.exec(["python", "-c", "print('log me')"]);

  const logs = await sandbox.logs({ limit: 100 });
  for (const line of logs) {
    console.log(`${line.timestamp} [${line.level}] ${line.line}`);
  }
} finally {
  await sandbox.terminate();
  porter.close();
}
```

## Get a sandbox by name

```typescript theme={null}
import { Porter } from "porter-sandbox";

const porter = new Porter();
const sandbox = await porter.sandboxes.get("typescript-quickstart");

console.log(sandbox.phase);
porter.close();
```

## List sandboxes

Use tags to find sandboxes created by a workflow:

```typescript theme={null}
import { Porter } from "porter-sandbox";

const porter = new Porter();

const sandboxes = await porter.sandboxes.list({
  tags: { workflow: "agent-run" },
});

for (const sandbox of sandboxes) {
  console.log(sandbox.phase);
}

porter.close();
```

## Concurrent sandboxes

All TypeScript Sandbox SDK methods are promise-based, so you can fan out with `Promise.all`:

```typescript theme={null}
const sandboxes = await Promise.all(
  Array.from({ length: 10 }, (_, index) =>
    porter.sandboxes.create({
      image: "python:3.12-slim",
      name: `batch-demo-${index}`,
      tags: { batch: "demo" },
    }),
  ),
);
```

## Next steps

* [TypeScript Sandbox SDK reference](/sandbox/sdk/typescript/reference)
* [TypeScript Sandbox SDK volumes](/sandbox/sdk/typescript/volumes)
* [TypeScript Sandbox SDK errors](/sandbox/sdk/typescript/errors)
* [Sandboxes getting started](/sandboxes/getting-started)
