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

# Manage sandboxes

> Create sandboxes with the TypeScript, Python, or Go SDK, the Baseten CLI, or the dashboard, and inspect, update, and delete them.

Create a sandbox for an agent's task, wait for it to deploy, and delete it when
the work finishes. Use a Baseten SDK to manage sandboxes from your application.
Each SDK creates and refreshes [sandbox access tokens](/sandboxes/authentication)
for you. Use the [Baseten CLI](/reference/cli/baseten/overview) or the dashboard
to inspect and troubleshoot sandboxes by hand.

You need permission to create resources in your team.

## Set up

Install the CLI or an SDK:

<Tabs>
  <Tab title="TypeScript">
    **To install the SDK**:

    Run the following command:

    ```bash theme={"system"}
    npm install @basetenlabs/sandbox undici
    ```

    Set `BASETEN_API_KEY` to a [Baseten API key](/organization/api-keys#create-an-api-key)
    for SDK authentication.
  </Tab>

  <Tab title="Python">
    **To install the SDK**:

    Run the following command:

    ```bash theme={"system"}
    pip install baseten "httpx[http2]"
    ```

    Set `BASETEN_API_KEY` to a [Baseten API key](/organization/api-keys#create-an-api-key)
    for SDK authentication.
  </Tab>

  <Tab title="Go">
    **To install the SDK**:

    Run the following command:

    ```bash theme={"system"}
    go get github.com/basetenlabs/baseten-go/sandbox
    ```

    Set `BASETEN_API_KEY` to a [Baseten API key](/organization/api-keys#create-an-api-key)
    for SDK authentication.
  </Tab>

  <Tab title="CLI">
    **To sign in**:

    [Install the Baseten CLI](/reference/cli/baseten/overview#install), then
    run the following command:

    ```bash theme={"system"}
    baseten auth login
    ```

    Sign in through your browser. CLI sign-in doesn't authenticate SDK
    applications; they use an API key.
  </Tab>
</Tabs>

Run the following command to set the sandbox name used by the CLI examples:

```bash theme={"system"}
export SANDBOX_NAME="hello-world"
```

<Note>
  Sandbox commands are in pre-release. Arguments, flags, and output may change.
</Note>

## Create a sandbox

Creating a sandbox starts an isolated environment from an image. The new
sandbox gets a name, an image, memory (which also sets its CPU allocation), and
a region. Name, image, memory, and region can't change after creation.

<Note>
  An organization can run up to 10 sandboxes at once. To raise this quota,
  contact [Baseten support](mailto:support@baseten.co) with your organization
  ID.
</Note>

<Tabs>
  <Tab title="TypeScript">
    **To create a sandbox**:

    Run the following code:

    ```typescript theme={"system"}
    import { SandboxClient } from "@basetenlabs/sandbox";

    const client = new SandboxClient({ apiKey: process.env.BASETEN_API_KEY! });
    const sandbox = await client.create({
      name: "hello-world",
      labels: { purpose: "hello-world" },
    });
    console.log(sandbox.name);
    ```

    The call waits until the sandbox is ready. To reuse a live sandbox with the
    same name, set `createIfNotExists: true`.
  </Tab>

  <Tab title="Python">
    **To create a sandbox**:

    Run the following code:

    ```python theme={"system"}
    import os

    from baseten.sandbox import SandboxClient

    with SandboxClient(api_key=os.environ["BASETEN_API_KEY"]) as client:
        sandbox = client.create(name="hello-world", labels={"purpose": "hello-world"})
        print(sandbox.name)
    ```

    The call waits until the sandbox is ready. To reuse a live sandbox with the
    same name, pass `create_if_not_exists=True`.
  </Tab>

  <Tab title="Go">
    **To create a sandbox**:

    Run the following code:

    ```go theme={"system"}
    package main

    import (
        "context"
        "fmt"
        "log"
        "os"

        "github.com/basetenlabs/baseten-go/sandbox"
    )

    func main() {
        ctx := context.Background()
        client, err := sandbox.NewClient(sandbox.ClientOptions{
            APIKey: os.Getenv("BASETEN_API_KEY"),
        })
        if err != nil {
            log.Fatal(err)
        }
        sb, err := client.Create(ctx, sandbox.CreateOptions{
            Name:   "hello-world",
            Labels: map[string]string{"purpose": "hello-world"},
        })
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(sb.Name())
    }
    ```

    The call waits until the sandbox is ready. To reuse a live sandbox with the
    same name, set `CreateIfNotExists: true`.
  </Tab>

  <Tab title="CLI">
    **To create a sandbox**:

    Run the following command:

    ```bash theme={"system"}
    baseten sandbox create --name "$SANDBOX_NAME" --label purpose=hello-world
    ```

    The command waits until the sandbox is ready, then prints its record with
    status `DEPLOYED`, so you can [run commands](#run-commands-in-a-sandbox) in
    it right away. Without flags, the sandbox uses **Base Image**, 4096 MiB,
    and the closest region. To use a different image, memory allocation, or
    region, run the following command:

    ```bash theme={"system"}
    baseten sandbox create --name "$SANDBOX_NAME" --image baseten/base-image:latest --memory 8192 --region us-was-1
    ```

    To reuse a live sandbox with the same name instead of failing on a name
    conflict, run the following command:

    ```bash theme={"system"}
    baseten sandbox create --name "$SANDBOX_NAME" --if-not-exists
    ```
  </Tab>

  <Tab title="UI">
    **To create a sandbox**:

    1. Sign in to your workspace at [app.baseten.co](https://app.baseten.co)
       and choose **Sandboxes** in the sidebar.
    2. Choose **Create sandbox**.
    3. Choose **Base Image**, or another [image](/sandboxes/manage-images) with the
       software your task needs.
    4. Enter a **Name**, for example, `hello-world`.
    5. For **Memory (MiB)**, keep the default or enter the memory the workload
       needs. More memory also means more CPU.
    6. Choose a **Region**.
    7. Optionally, for **Time to live**, choose how long the sandbox can run
       before Baseten deletes it.
    8. If the form shows **Team**, choose the team that should own the sandbox.
    9. Optionally, [add environment variables](#set-environment-variables).
    10. Choose **Create sandbox**.

    If the form reports an error, check the validation message next to each
    field. For common causes, see [Handle a failed command](#handle-a-failed-command).
  </Tab>
</Tabs>

## Get a sandbox

A sandbox's record shows its configuration, URL, and current status.

<Tabs>
  <Tab title="TypeScript">
    **To check a sandbox's status**:

    Run the following code:

    ```typescript theme={"system"}
    import { SandboxClient } from "@basetenlabs/sandbox";

    const client = new SandboxClient({ apiKey: process.env.BASETEN_API_KEY! });
    const info = await client.getInfo({ name: "hello-world" });
    console.log(info.status);
    ```

    To work with the sandbox, not just its record, use
    `client.get({ name: "hello-world" })`.
  </Tab>

  <Tab title="Python">
    **To check a sandbox's status**:

    Run the following code:

    ```python theme={"system"}
    import os

    from baseten.sandbox import SandboxClient

    with SandboxClient(api_key=os.environ["BASETEN_API_KEY"]) as client:
        info = client.get_info(name="hello-world")
        print(info.status)
    ```

    To work with the sandbox, not just its record, use
    `sandbox = client.get(name="hello-world")`.
  </Tab>

  <Tab title="Go">
    **To check a sandbox's status**:

    Run the following code:

    ```go theme={"system"}
    package main

    import (
        "context"
        "fmt"
        "log"
        "os"

        "github.com/basetenlabs/baseten-go/sandbox"
    )

    func main() {
        ctx := context.Background()
        client, err := sandbox.NewClient(sandbox.ClientOptions{
            APIKey: os.Getenv("BASETEN_API_KEY"),
        })
        if err != nil {
            log.Fatal(err)
        }
        info, err := client.GetInfo(ctx, sandbox.GetInfoOptions{Name: "hello-world"})
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(info.Status)
    }
    ```

    To work with the sandbox, not just its record, use
    `client.Get(ctx, sandbox.GetOptions{Name: "hello-world"})`.
  </Tab>

  <Tab title="CLI">
    **To check a sandbox's status**:

    Run the following command:

    <CodeGroup>
      ```bash Command theme={"system"}
      baseten sandbox describe --name "$SANDBOX_NAME"
      ```

      ```txt Output theme={"system"}
      Name:         hello-world
      Status:       DEPLOYED
      URL:          <SANDBOX_URL>
      Image:        baseten/base-image:latest
      Memory:       4096 MB
      Region:       us-was-1
      Labels:       purpose=hello-world
      Ports:        8080
      Created:      2026-10-07T17:28:19Z
      ```
    </CodeGroup>

    To print only the sandbox's status, run the following command:

    <CodeGroup>
      ```bash Command theme={"system"}
      baseten sandbox describe --name "$SANDBOX_NAME" --jq '.status'
      ```

      ```txt Output theme={"system"}
      "DEPLOYED"
      ```
    </CodeGroup>
  </Tab>

  <Tab title="UI">
    In **Sandboxes**, choose the sandbox. Its detail page shows the same
    status.
  </Tab>
</Tabs>

If the status is `FAILED`, inspect the sandbox's [logs](/sandboxes/logs)
before retrying. For the deployment and deletion statuses, see
[Lifecycle and expiration](/sandboxes/lifecycle).

## Interact with a running sandbox

You can interact with a sandbox in two ways:

* Use the [Management API](/reference/management-api/sandboxes/overview),
  through the CLI or an SDK, to:
  * Create sandboxes.
  * List sandboxes.
  * Update sandboxes.
  * Delete sandboxes.
* Use the sandbox's own API, served by a server inside each sandbox at the
  sandbox's `url` field, to:
  * Run commands.
  * Read, write, and edit files.

The sandbox's server URL is the `url` field the create or get call returns.
Get the URL before connecting:

<Tabs>
  <Tab title="Python">
    **To get the sandbox's server URL**:

    Run the following code:

    <CodeGroup>
      ```python Command theme={"system"}
      import os

      from baseten.sandbox import SandboxClient

      with SandboxClient(api_key=os.environ["BASETEN_API_KEY"]) as client:
          sandbox = client.get(name="hello-world")
          print(sandbox.url)
      ```

      ```txt Output theme={"system"}
      https://sbx-hello-world-abc123.us-pdx-1.b10.co/
      ```
    </CodeGroup>
  </Tab>

  <Tab title="CLI">
    **To get the sandbox's server URL**:

    Run the following command:

    <CodeGroup>
      ```bash Command theme={"system"}
      baseten sandbox describe --name "$SANDBOX_NAME" --jq '.url'
      ```

      ```txt Output theme={"system"}
      "https://sbx-hello-world-abc123.us-pdx-1.b10.co"
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Dashboard">
    **To get the sandbox's server URL**:

    1. Sign in to your workspace at [app.baseten.co](https://app.baseten.co)
       and choose **Sandboxes** in the sidebar, then choose the sandbox.
    2. On **Overview**, choose **Connect**.
    3. In the **Connect to sandbox** dialog, choose a tab and copy its value.
  </Tab>
</Tabs>

Use the URL exactly as the API returns it. Direct HTTP calls and MCP
clients need it, and the CLI and SDKs look it up for you:

<img className="block dark:hidden" src="https://mintcdn.com/baseten-preview/5_CTBHN9TPuoX1ef/_images/sandbox-url-anatomy-light.svg?fit=max&auto=format&n=5_CTBHN9TPuoX1ef&q=85&s=ec673cfc1f987ccf70fbfb9f38b8a2ba" alt="Anatomy of a sandbox server URL. In https://sbx-hello-world-abc123.us-pdx-1.b10.co, hello-world is the sandbox name, abc123 identifies the sandbox's team, and us-pdx-1 is the region." width="900" height="190" data-path="_images/sandbox-url-anatomy-light.svg" />

<img className="hidden dark:block" src="https://mintcdn.com/baseten-preview/5_CTBHN9TPuoX1ef/_images/sandbox-url-anatomy-dark.svg?fit=max&auto=format&n=5_CTBHN9TPuoX1ef&q=85&s=7178113b157290e97fae15147b62af50" alt="Anatomy of a sandbox server URL. In https://sbx-hello-world-abc123.us-pdx-1.b10.co, hello-world is the sandbox name, abc123 identifies the sandbox's team, and us-pdx-1 is the region." width="900" height="190" data-path="_images/sandbox-url-anatomy-dark.svg" />

**To connect to a sandbox**:

Connect with an interactive terminal, direct HTTP calls, an SDK, or an MCP
client:

<Tabs>
  <Tab title="Python">
    **To write and read a file through the SDK**:

    Run the following code:

    ```python theme={"system"}
    import os

    from baseten.sandbox import SandboxClient

    with SandboxClient(api_key=os.environ["BASETEN_API_KEY"]) as client:
        sandbox = client.get(name="hello-world")
        sandbox.fs.write(path="/tmp/hello.txt", content="hello")
        result = sandbox.process.exec(
            command="cat /tmp/hello.txt", wait_for_completion=True
        )
        print(result.stdout)
    ```

    For operations the SDK doesn't wrap, `sandbox.raw_api` is the generated client,
    and `client.sandbox_from_url(url=...)` builds a sandbox from a URL you
    already have.
  </Tab>

  <Tab title="HTTP">
    **To send an authenticated request to the sandbox**:

    Request a [sandbox access token](/sandboxes/authentication), then run the
    following command:

    ```bash theme={"system"}
    curl --url "<sandbox-url>" \
      --header "Authorization: Bearer $SANDBOX_TOKEN"
    ```

    The sandbox's OpenAPI spec is at `<sandbox-url>/v1/spec`.
  </Tab>

  <Tab title="CLI">
    **To open an interactive terminal in the sandbox**:

    Run the following command:

    ```bash theme={"system"}
    baseten sandbox connect --name "$SANDBOX_NAME"
    ```

    Opens an interactive terminal in the sandbox. Press **Ctrl+D** to
    disconnect.
  </Tab>

  <Tab title="MCP server">
    **To connect an MCP client to the sandbox**:

    Request a [sandbox access token](/sandboxes/authentication), then configure
    your MCP client with the following endpoint and authorization header:

    ```text theme={"system"}
    https://<sandbox-url>/mcp
    Authorization: Bearer <SANDBOX_TOKEN>
    ```

    An MCP client connected to the sandbox gets ready-made tools for running
    commands and for reading, writing, and editing files.
  </Tab>
</Tabs>

Applications that need tighter control than the MCP server's tools define
their own functions instead. The sandbox's MCP server is separate from the
Baseten MCP, which manages deployments and models across your workspace.

## Run commands in a sandbox

Run a single command in a deployed sandbox. Its output streams to your
terminal, and its exit code becomes the command's exit code.

<Tabs>
  <Tab title="TypeScript">
    **To check the sandbox's Python version**:

    Run the following code:

    ```typescript theme={"system"}
    import { SandboxClient } from "@basetenlabs/sandbox";

    const client = new SandboxClient({ apiKey: process.env.BASETEN_API_KEY! });
    const sandbox = await client.get({ name: "hello-world" });
    const result = await sandbox.process.exec({
      command: "python3 --version",
      waitForCompletion: true,
    });
    console.log(result.stdout, result.exitCode);
    ```

    **To add environment variables for one command**:

    Replace `worker.py` with the path to your script in the sandbox, then
    update the example as follows:

    ```typescript theme={"system"}
    const result = await sandbox.process.exec({
      command: "python3 worker.py",
      env: { LOG_LEVEL: "debug" },
      waitForCompletion: true,
    });
    ```
  </Tab>

  <Tab title="Python">
    **To check the sandbox's Python version**:

    Run the following code:

    ```python theme={"system"}
    import os

    from baseten.sandbox import SandboxClient

    with SandboxClient(api_key=os.environ["BASETEN_API_KEY"]) as client:
        sandbox = client.get(name="hello-world")
        result = sandbox.process.exec(command="python3 --version", wait_for_completion=True)
        print(result.stdout, result.exit_code)
    ```

    **To add environment variables for one command**:

    Replace `worker.py` with the path to your script in the sandbox, then
    update the example as follows:

    ```python theme={"system"}
    result = sandbox.process.exec(
        command="python3 worker.py",
        env={"LOG_LEVEL": "debug"},
        wait_for_completion=True,
    )
    ```
  </Tab>

  <Tab title="Go">
    **To check the sandbox's Python version**:

    Run the following code:

    ```go theme={"system"}
    package main

    import (
        "context"
        "fmt"
        "log"
        "os"

        "github.com/basetenlabs/baseten-go/sandbox"
    )

    func main() {
        ctx := context.Background()
        client, err := sandbox.NewClient(sandbox.ClientOptions{
            APIKey: os.Getenv("BASETEN_API_KEY"),
        })
        if err != nil {
            log.Fatal(err)
        }
        sb, err := client.Get(ctx, sandbox.GetOptions{Name: "hello-world"})
        if err != nil {
            log.Fatal(err)
        }
        process, err := sb.Process().Exec(ctx, sandbox.ProcessExecOptions{
            Command:           "python3 --version",
            WaitForCompletion: true,
        })
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(process.Stdout, process.ExitCode)
    }
    ```

    **To add environment variables for one command**:

    Replace `worker.py` with the path to your script in the sandbox, then
    update the example as follows:

    ```go theme={"system"}
    process, err := sb.Process().Exec(ctx, sandbox.ProcessExecOptions{
        Command:           "python3 worker.py",
        Env:               map[string]string{"LOG_LEVEL": "debug"},
        WaitForCompletion: true,
    })
    ```
  </Tab>

  <Tab title="CLI">
    **To check the sandbox's Python version**:

    Run the following command:

    <CodeGroup>
      ```bash Command theme={"system"}
      baseten sandbox exec --name "$SANDBOX_NAME" -- python3 --version
      ```

      ```txt Output theme={"system"}
      Python 3.12.15
      ```
    </CodeGroup>

    **To add environment variables for one command**:

    Replace `worker.py` with the path to your script in the sandbox, then
    run the following command:

    ```bash theme={"system"}
    baseten sandbox exec --name "$SANDBOX_NAME" --env LOG_LEVEL=debug -- python3 worker.py
    ```

    For an interactive terminal, see [Connect to a sandbox](#interact-with-a-running-sandbox).
  </Tab>
</Tabs>

## Access an HTTP service

Start an HTTP service in a sandbox, then send requests through the sandbox
API server's `/port/<PORT>/` route. The service must be listening before
you send the request.

Use a running `hello-world` sandbox created from an image that includes
Python, such as **Base Image**. [Set up your SDK or CLI](#set-up). For the SDK examples, set
`BASETEN_API_KEY`. For every tab, [request a sandbox access token](/sandboxes/authentication)
and set `SANDBOX_TOKEN` in your local environment. Direct HTTP requests need
this token even when an SDK starts the service.

<Tabs>
  <Tab title="TypeScript">
    **To call an HTTP service**:

    Run the following code to start the server, wait until it listens on port
    `8000`, send a request, and stop the server:

    <CodeGroup>
      ```typescript Code theme={"system"}
      import { SandboxClient } from "@basetenlabs/sandbox";

      const client = new SandboxClient({ apiKey: process.env.BASETEN_API_KEY! });
      const sandbox = await client.get({ name: "hello-world" });
      await sandbox.process.exec({
        command: "python3 -m http.server 8000",
        name: "web",
        waitForPorts: [8000],
      });
      try {
        const response = await fetch(`${sandbox.url.replace(/\/$/, "")}/port/8000/`, {
          headers: { Authorization: `Bearer ${process.env.SANDBOX_TOKEN}` },
        });
        console.log(await response.text());
      } finally {
        await sandbox.process.stop({ identifier: "web" });
      }
      ```

      ```txt Output theme={"system"}
      <!DOCTYPE HTML>
      <html lang="en">
      <head>
      <meta charset="utf-8">
      <title>Directory listing for /</title>
      ...
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Python">
    **To call an HTTP service**:

    Run the following code to start the server, wait until it listens on port
    `8000`, send a request, and stop the server:

    <CodeGroup>
      ```python Code theme={"system"}
      import os
      from urllib.request import Request, urlopen

      from baseten.sandbox import SandboxClient

      with SandboxClient(api_key=os.environ["BASETEN_API_KEY"]) as client:
          sandbox = client.get(name="hello-world")
          sandbox.process.exec(
              command="python3 -m http.server 8000",
              name="web",
              wait_for_ports=[8000],
          )
          try:
              request = Request(
                  f"{sandbox.url.rstrip('/')}/port/8000/",
                  headers={"Authorization": f"Bearer {os.environ['SANDBOX_TOKEN']}"},
              )
              with urlopen(request) as response:
                  print(response.read().decode())
          finally:
              sandbox.process.stop(identifier="web")
      ```

      ```txt Output theme={"system"}
      <!DOCTYPE HTML>
      <html lang="en">
      <head>
      <meta charset="utf-8">
      <title>Directory listing for /</title>
      ...
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Go">
    **To call an HTTP service**:

    Run the following code to start the server, wait until it listens on port
    `8000`, send a request, and stop the server:

    <CodeGroup>
      ```go Code theme={"system"}
      package main

      import (
          "context"
          "io"
          "log"
          "net/http"
          "os"
          "strings"

          "github.com/basetenlabs/baseten-go/sandbox"
      )

      func main() {
          ctx := context.Background()
          client, err := sandbox.NewClient(sandbox.ClientOptions{
              APIKey: os.Getenv("BASETEN_API_KEY"),
          })
          if err != nil {
              log.Fatal(err)
          }
          sb, err := client.Get(ctx, sandbox.GetOptions{Name: "hello-world"})
          if err != nil {
              log.Fatal(err)
          }
          _, err = sb.Process().Exec(ctx, sandbox.ProcessExecOptions{
              Command:      "python3 -m http.server 8000",
              Name:         "web",
              WaitForPorts: []int{8000},
          })
          if err != nil {
              log.Fatal(err)
          }
          defer sb.Process().Stop(ctx, sandbox.ProcessStopOptions{Identifier: "web"})

          request, err := http.NewRequestWithContext(ctx, http.MethodGet, strings.TrimRight(sb.URL(), "/")+"/port/8000/", nil)
          if err != nil {
              log.Print(err)
              return
          }
          request.Header.Set("Authorization", "Bearer "+os.Getenv("SANDBOX_TOKEN"))
          response, err := http.DefaultClient.Do(request)
          if err != nil {
              log.Print(err)
              return
          }
          defer response.Body.Close()
          if _, err := io.Copy(os.Stdout, response.Body); err != nil {
              log.Print(err)
          }
      }
      ```

      ```txt Output theme={"system"}
      <!DOCTYPE HTML>
      <html lang="en">
      <head>
      <meta charset="utf-8">
      <title>Directory listing for /</title>
      ...
      ```
    </CodeGroup>
  </Tab>

  <Tab title="CLI and cURL">
    **To call an HTTP service**:

    Set `SANDBOX_NAME` to `hello-world` and `SANDBOX_URL` to its returned
    `url` before running these commands.

    1. Run the following command to start the server and wait until it listens
       on port `8000`:

       ```bash theme={"system"}
       baseten sandbox process start --name "$SANDBOX_NAME" \
         --process-name web --wait-for-port 8000 -- python3 -m http.server 8000
       ```

    2. Run the following command to request the server's directory listing:

           <CodeGroup>
             ```bash Command theme={"system"}
             curl --url "${SANDBOX_URL%/}/port/8000/" \
               --header "Authorization: Bearer $SANDBOX_TOKEN"
             ```

             ```txt Output theme={"system"}
             <!DOCTYPE HTML>
             <html lang="en">
             <head>
             <meta charset="utf-8">
             <title>Directory listing for /</title>
             ...
             ```
           </CodeGroup>

    3. When you're finished, run the following command to stop the server:

       ```bash theme={"system"}
       baseten sandbox process stop --name "$SANDBOX_NAME" --process-name web
       ```
  </Tab>
</Tabs>

A successful request returns HTTP `200` with Python's directory listing.
Requests without the sandbox access token return HTTP `401`.

## Set environment variables

Environment variables pass configuration, such as an output format or log
level, to the processes in a sandbox, so one image can serve different tasks.
Set them at creation. Names begin with a letter or underscore and contain only
letters, digits, and underscores. Don't put your Baseten API key in a
sandbox's environment.

<Tabs>
  <Tab title="TypeScript">
    **To create a sandbox with environment variables**:

    Run the following code:

    ```typescript theme={"system"}
    import { SandboxClient } from "@basetenlabs/sandbox";

    const client = new SandboxClient({ apiKey: process.env.BASETEN_API_KEY! });
    const sandbox = await client.create({
      name: "hello-world",
      envs: {
        DB_PASSWORD: { value: "secret" },
        OUTPUT_FORMAT: { value: "json", secret: false },
      },
    });
    console.log(sandbox.name);
    ```

    Set `secret: false` for a value you want to read back later.
  </Tab>

  <Tab title="Python">
    **To create a sandbox with environment variables**:

    Run the following code:

    ```python theme={"system"}
    import os

    from baseten.sandbox import SandboxClient, SandboxEnvValue

    with SandboxClient(api_key=os.environ["BASETEN_API_KEY"]) as client:
        sandbox = client.create(
            name="hello-world",
            envs={
                "DB_PASSWORD": SandboxEnvValue(value="secret"),
                "OUTPUT_FORMAT": SandboxEnvValue(value="json", secret=False),
            },
        )
        print(sandbox.name)
    ```

    Set `secret=False` for a value you want to read back later.
  </Tab>

  <Tab title="Go">
    **To create a sandbox with environment variables**:

    Run the following code:

    ```go theme={"system"}
    package main

    import (
        "context"
        "fmt"
        "log"
        "os"

        "github.com/basetenlabs/baseten-go/sandbox"
    )

    func main() {
        ctx := context.Background()
        client, err := sandbox.NewClient(sandbox.ClientOptions{
            APIKey: os.Getenv("BASETEN_API_KEY"),
        })
        if err != nil {
            log.Fatal(err)
        }
        sb, err := client.Create(ctx, sandbox.CreateOptions{
            Name: "hello-world",
            Envs: map[string]sandbox.EnvValue{
                "DB_PASSWORD":   {Value: "secret"},
                "OUTPUT_FORMAT": {Value: "json", NonSecret: true},
            },
        })
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(sb.Name())
    }
    ```

    Set `NonSecret: true` for a value you want to read back later.
  </Tab>

  <Tab title="CLI">
    **To create a sandbox with environment variables**:

    Run the following command:

    ```bash theme={"system"}
    baseten sandbox create --name "$SANDBOX_NAME" --env DB_PASSWORD=secret --plain-env OUTPUT_FORMAT=json
    ```

    `--env` marks the value secret; `--plain-env` leaves it readable. To
    verify a value after deployment, run the following command:

    <CodeGroup>
      ```bash Command theme={"system"}
      baseten sandbox exec --name "$SANDBOX_NAME" -- 'echo $OUTPUT_FORMAT'
      ```

      ```txt Output theme={"system"}
      json
      ```
    </CodeGroup>
  </Tab>

  <Tab title="UI">
    **To set environment variables**:

    1. In **Sandboxes**, choose **Create sandbox**, then choose an image.
    2. Under **Environment variables**, choose **Add variable**.
    3. Type a name and value, such as `OUTPUT_FORMAT` and `json`.
    4. Repeat steps 2 and 3 for each additional variable.
  </Tab>
</Tabs>

Values are secret by default. Secret values are masked as `****` when you read
them back, so use them for credentials and tokens. For configuration you'll
want to see later, such as `LOG_LEVEL` or `OUTPUT_FORMAT`, mark the value as
not secret so it stays readable. A `describe` shows the difference:

```txt theme={"system"}
[
  { "name": "DB_PASSWORD", "secret": true,  "value": "****" },
  { "name": "LOG_LEVEL",   "secret": false, "value": "info" }
]
```

To read a secret value back, add `--show-secrets` to `describe`, or read the
variable inside the sandbox. Don't pass `--plain-env` or `secret: false` for
credentials; those values are stored and returned in plain text.

## List sandboxes

<Tabs>
  <Tab title="TypeScript">
    **To list sandboxes**:

    Run the following code:

    ```typescript theme={"system"}
    import { SandboxClient } from "@basetenlabs/sandbox";

    const client = new SandboxClient({ apiKey: process.env.BASETEN_API_KEY! });
    for await (const sandbox of client.list({ query: "hello" })) {
      console.log(sandbox.name, sandbox.status);
    }
    ```

    Filter by status with `statuses`, such as `statuses: ["DEPLOYED"]`.
  </Tab>

  <Tab title="Python">
    **To list sandboxes**:

    Run the following code:

    ```python theme={"system"}
    import os

    from baseten.sandbox import SandboxClient

    with SandboxClient(api_key=os.environ["BASETEN_API_KEY"]) as client:
        for sandbox in client.list(query="hello"):
            print(sandbox.name, sandbox.status)
    ```

    Filter by status with `statuses`, such as `statuses=["DEPLOYED"]`.
  </Tab>

  <Tab title="Go">
    **To list sandboxes**:

    Run the following code:

    ```go theme={"system"}
    package main

    import (
        "context"
        "fmt"
        "log"
        "os"

        "github.com/basetenlabs/baseten-go/sandbox"
    )

    func main() {
        ctx := context.Background()
        client, err := sandbox.NewClient(sandbox.ClientOptions{
            APIKey: os.Getenv("BASETEN_API_KEY"),
        })
        if err != nil {
            log.Fatal(err)
        }
        for info, err := range client.List(ctx, sandbox.ListOptions{Query: "hello"}) {
            if err != nil {
                log.Fatal(err)
            }
            fmt.Println(info.Name, info.Status)
        }
    }
    ```

    Filter by status with `Statuses`, such as
    `Statuses: []sandbox.Status{sandbox.StatusDeployed}`.
  </Tab>

  <Tab title="CLI">
    **To list sandboxes**:

    Run the following command:

    <CodeGroup>
      ```bash Command theme={"system"}
      baseten sandbox list
      ```

      ```txt Output theme={"system"}
      NAME         STATUS    REGION    CREATED
      hello-world  DEPLOYED  us-was-1  2026-10-07T17:28:19Z
      ```
    </CodeGroup>

    The output lists every sandbox in the team, except terminated ones. To
    filter by status or search names and labels, run the following commands:

    ```bash theme={"system"}
    baseten sandbox list --status deployed
    baseten sandbox list --query docs
    ```
  </Tab>
</Tabs>

## Manage a sandbox's labels

Labels help you find and group sandboxes, such as marking every sandbox an
agent creates with `purpose=agent`. This example changes the `purpose` label
from `hello-world` to `hello-universe`:

<Tabs>
  <Tab title="TypeScript">
    **To change a sandbox's labels**:

    Run the following code:

    ```typescript theme={"system"}
    import { SandboxClient } from "@basetenlabs/sandbox";

    const client = new SandboxClient({ apiKey: process.env.BASETEN_API_KEY! });
    const updated = await client.update({
      name: "hello-world",
      labels: { purpose: "hello-universe" },
    });
    console.log(updated.labels);
    ```
  </Tab>

  <Tab title="Python">
    **To change a sandbox's labels**:

    Run the following code:

    ```python theme={"system"}
    import os

    from baseten.sandbox import SandboxClient

    with SandboxClient(api_key=os.environ["BASETEN_API_KEY"]) as client:
        info = client.update(name="hello-world", labels={"purpose": "hello-universe"})
        print(info.labels)
    ```
  </Tab>

  <Tab title="Go">
    **To change a sandbox's labels**:

    Run the following code:

    ```go theme={"system"}
    package main

    import (
        "context"
        "fmt"
        "log"
        "os"

        "github.com/basetenlabs/baseten-go/sandbox"
    )

    func main() {
        ctx := context.Background()
        client, err := sandbox.NewClient(sandbox.ClientOptions{
            APIKey: os.Getenv("BASETEN_API_KEY"),
        })
        if err != nil {
            log.Fatal(err)
        }
        updated, err := client.Update(ctx, sandbox.UpdateOptions{
            Name:   "hello-world",
            Labels: map[string]string{"purpose": "hello-universe"},
        })
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(updated.Labels)
    }
    ```
  </Tab>

  <Tab title="CLI">
    **To change a sandbox's labels**:

    Run the following command:

    ```bash theme={"system"}
    baseten sandbox update --name "$SANDBOX_NAME" --label purpose=hello-universe
    ```

    The command prints the updated sandbox.
  </Tab>

  <Tab title="UI">
    **To change a sandbox's labels**:

    1. In **Sandboxes**, choose the sandbox.
    2. Choose **Sandbox settings**.
    3. Under **Labels**, add, change, or remove labels.
    4. Choose **Save changes**.

    **Sandbox settings** is unavailable while a sandbox is deleting or
    archived.
  </Tab>
</Tabs>

A supplied set of labels replaces all previous labels, so include every one you
want to keep. Omitted fields leave their values unchanged. You can also update
environment variables with `envs`.

The name, image, memory, and region can't change after creation. To use a
different image, [create a new sandbox](#create-a-sandbox).

## Delete a sandbox

Deletion stops the sandbox's processes and permanently removes its files, so
save the files you need first.

<Tabs>
  <Tab title="TypeScript">
    **To delete a sandbox**:

    Run the following code:

    ```typescript theme={"system"}
    import { SandboxClient } from "@basetenlabs/sandbox";

    const client = new SandboxClient({ apiKey: process.env.BASETEN_API_KEY! });
    await client.delete({ name: "hello-world" });
    ```
  </Tab>

  <Tab title="Python">
    **To delete a sandbox**:

    Run the following code:

    ```python theme={"system"}
    import os

    from baseten.sandbox import SandboxClient

    with SandboxClient(api_key=os.environ["BASETEN_API_KEY"]) as client:
        client.delete(name="hello-world")
    ```
  </Tab>

  <Tab title="Go">
    **To delete a sandbox**:

    Run the following code:

    ```go theme={"system"}
    package main

    import (
        "context"
        "log"
        "os"

        "github.com/basetenlabs/baseten-go/sandbox"
    )

    func main() {
        ctx := context.Background()
        client, err := sandbox.NewClient(sandbox.ClientOptions{
            APIKey: os.Getenv("BASETEN_API_KEY"),
        })
        if err != nil {
            log.Fatal(err)
        }
        if _, err := client.Delete(ctx, sandbox.DeleteOptions{Name: "hello-world"}); err != nil {
            log.Fatal(err)
        }
    }
    ```
  </Tab>

  <Tab title="CLI">
    **To delete a sandbox**:

    Run the following command:

    ```bash theme={"system"}
    baseten sandbox delete --name "$SANDBOX_NAME"
    ```

    Confirm when prompted. For unattended scripts, `--yes` skips confirmation.
  </Tab>

  <Tab title="UI">
    **To delete a sandbox**:

    1. In **Sandboxes**, choose the sandbox.
    2. Choose **Delete sandbox**.
    3. Type the sandbox's name to confirm, then choose **Delete sandbox**.
  </Tab>
</Tabs>

Deletion continues after the call returns. Stop sending work to the sandbox,
then [describe the sandbox](#get-a-sandbox) until its status is `TERMINATED`.
The sandbox reports `TERMINATED` for a few minutes, and then it's no longer
found. Don't reuse the name until deletion completes.

## Work in a team

If you belong to multiple teams, specify a team ID when you create an SDK client:

<Tabs>
  <Tab title="TypeScript">
    **To select a team for SDK requests**:

    Replace `<TEAM_ID>` with your team's ID, then configure the client as follows:

    ```typescript theme={"system"}
    import { SandboxClient } from "@basetenlabs/sandbox";

    const client = new SandboxClient({
      apiKey: process.env.BASETEN_API_KEY!,
      teamId: "<TEAM_ID>",
    });
    ```
  </Tab>

  <Tab title="Python">
    **To select a team for SDK requests**:

    Replace `<TEAM_ID>` with your team's ID, then configure the client as follows:

    ```python theme={"system"}
    import os

    from baseten.sandbox import SandboxClient

    client = SandboxClient(api_key=os.environ["BASETEN_API_KEY"], team_id="<TEAM_ID>")
    ```
  </Tab>

  <Tab title="Go">
    **To select a team for SDK requests**:

    Replace `<TEAM_ID>` with your team's ID, then configure the client as follows:

    ```go theme={"system"}
    package main

    import (
        "log"
        "os"

        "github.com/basetenlabs/baseten-go/sandbox"
    )

    func main() {
        _, err := sandbox.NewClient(sandbox.ClientOptions{
            APIKey: os.Getenv("BASETEN_API_KEY"),
            TeamID: "<TEAM_ID>",
        })
        if err != nil {
            log.Fatal(err)
        }
    }
    ```
  </Tab>

  <Tab title="CLI">
    **To manage sandboxes in another team**:

    The CLI uses your organization's default team. Run the following command
    to list your organization's teams:

    ```bash theme={"system"}
    baseten org team list
    ```

    Replace `<TEAM_ID>` with the selected team's ID, then run the following command:

    ```bash theme={"system"}
    baseten sandbox list --team <TEAM_ID>
    ```

    Use the same team for every command that manages a particular sandbox.
  </Tab>
</Tabs>

## Handle a failed command

Use the error message to choose the next action:

| Error | Check |
| - | - |
| Not authenticated | Run `baseten auth status`, then `baseten auth login` or set `BASETEN_API_KEY`. |
| Permission denied | Sandboxes access for your organization and your permissions in the team. |
| Invalid name on create | The name must be 1 to 49 lowercase letters, digits, or hyphens, and start and end with a letter or digit. |
| Name conflict on create | Choose an unused name, or add `--if-not-exists` to reuse the live sandbox. |
| `Quota exceeded: 10/10 sandboxes` on create | Your organization is at its sandbox quota. Delete sandboxes you no longer need, or contact [Baseten support](mailto:support@baseten.co) with your organization ID to raise it. |
| Conflict on delete | The sandbox is in use or conflicts with the request. Retry after its current operation finishes. |
| Invalid update | An immutable field or an invalid value. |
| Team required | For SDK clients, specify a team ID if you belong to multiple teams. For CLI commands, specify a team ID if your organization has no default team. See [Work in a team](#work-in-a-team) for examples. |

## Next steps

<CardGroup cols={2}>
  <Card title="Sandbox lifecycle and expiration" icon="clock" href="/sandboxes/lifecycle">
    Track deployment status and set an expiration policy.
  </Card>

  <Card title="Manage sandbox images" icon="box" href="/sandboxes/manage-images">
    Choose a built-in image, or create and version your own.
  </Card>
</CardGroup>
