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

# Sandbox Pools

> Pre-warm sandboxes with pools for near-instant startup

A Sandbox Pool is a sandbox template — image, resources, entrypoint, timeout, network policy — plus a set of pre-booted warm containers. Creating a sandbox from a pool claims a warm container instead of cold-booting one, so the sandbox is ready almost instantly.

How it works:

* The pool keeps `warm_containers` idle containers booted and waiting.
* Creating a sandbox from the pool claims a warm container if one is available; otherwise a new container cold-starts on demand.
* After a claim, the pool boots a replacement to restore the warm buffer.
* `max_containers` caps the pool's total (warm + claimed) containers. At the cap, new sandboxes stay `pending` until a slot frees up.

Sandboxes claimed from a pool inherit the pool's image, resources, entrypoint, timeout, and network policy — you cannot override them per sandbox.

## Creating a Pool

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from tensorlake.sandbox import SandboxClient

    client = SandboxClient.for_cloud()

    pool = client.create_pool(
        image="tensorlake/ubuntu-minimal",
        cpus=1.0,
        memory_mb=1024,
        warm_containers=2,
        max_containers=10,
    )
    print(pool.pool_id)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import { SandboxClient } from "tensorlake";

    const client = new SandboxClient();

    const pool = await client.createPool({
      image: "tensorlake/ubuntu-minimal",
      cpus: 1.0,
      memoryMb: 1024,
      warmContainers: 2,
      maxContainers: 10,
    });
    console.log(pool.poolId);
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl -X POST https://api.tensorlake.ai/sandbox-pools \
      -H "Authorization: Bearer $TL_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "image": "tensorlake/ubuntu-minimal",
        "resources": {"cpus": 1.0, "memory_mb": 1024},
        "warm_containers": 2,
        "max_containers": 10
      }'
    ```
  </Tab>

  <Tab title="CLI">
    Not supported in the CLI.
  </Tab>
</Tabs>

### Pool configuration

| Field             | Type        | Default            | Description                                                                              |
| ----------------- | ----------- | ------------------ | ---------------------------------------------------------------------------------------- |
| `image`           | `str`       | —                  | Sandbox image for containers in the pool. Required.                                      |
| `cpus`            | `float`     | `1.0`              | CPU cores per container (max 16)                                                         |
| `memory_mb`       | `int`       | `1024`             | Memory per container in MB (max 65536; must be 1000–8192 MB per CPU core)                |
| `warm_containers` | `int`       | `None`             | Number of idle, pre-booted containers to keep ready. Set `0` to scale to zero when idle. |
| `max_containers`  | `int`       | `None` (unbounded) | Cap on total containers, warm and claimed                                                |
| `timeout_secs`    | `int`       | `0` (no timeout)   | Timeout applied to sandboxes created from the pool                                       |
| `entrypoint`      | `list[str]` | `None`             | Entrypoint command for pool containers                                                   |

The HTTP API additionally accepts `exposed_ports`, `network` (egress policy), and `allow_unauthenticated_access`, with the same semantics as [sandbox creation](/sandboxes/lifecycle). Root disk size is server-managed for pool containers; `ephemeral_disk_mb` is accepted but ignored.

## Creating a Sandbox from a Pool

Pass `pool_id` to `Sandbox.create()`. This claims a warm container when one is available.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from tensorlake.sandbox import Sandbox

    with Sandbox.create(pool_id=pool.pool_id) as sandbox:
        result = sandbox.run("echo", ["hello from the pool"])
        print(result.stdout)
    # Sandbox terminates on exit; the pool boots a replacement warm container.
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import { Sandbox } from "tensorlake";

    const sandbox = await Sandbox.create({ poolId: pool.poolId });

    const result = await sandbox.run("echo", {
      args: ["hello from the pool"],
    });
    console.log(result.stdout);

    await sandbox.terminate();
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl -X POST https://api.tensorlake.ai/sandbox-pools/<pool-id>/sandboxes \
      -H "Authorization: Bearer $TL_API_KEY"
    ```

    Returns `sandbox_id` with status `pending`; poll the sandbox until it is `running`.
  </Tab>

  <Tab title="CLI">
    Not supported in the CLI.
  </Tab>
</Tabs>

<Note>
  When claiming from a pool, the sandbox `name` and `file_systems` parameters are ignored — the container is already booted from the pool's template.
</Note>

## Managing Pools

### Get a Pool

`get_pool` returns the pool configuration plus its current containers. Containers with no `sandbox_id` are warm and unclaimed.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    info = client.get_pool(pool.pool_id)
    print(info.image, info.warm_containers, info.max_containers)
    for c in info.containers or []:
        print(c.id, c.state, c.sandbox_id or "warm")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const info = await client.getPool(pool.poolId);
    console.log(info.image, info.warmContainers, info.maxContainers);
    for (const c of info.containers ?? []) {
      console.log(c.id, c.state, c.sandboxId ?? "warm");
    }
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl https://api.tensorlake.ai/sandbox-pools/<pool-id> \
      -H "Authorization: Bearer $TL_API_KEY"
    ```
  </Tab>
</Tabs>

### List Pools

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    for p in client.list_pools():
        print(p.pool_id, p.image)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const pools = await client.listPools();
    for (const p of pools) {
      console.log(p.poolId, p.image);
    }
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl https://api.tensorlake.ai/sandbox-pools \
      -H "Authorization: Bearer $TL_API_KEY"
    ```
  </Tab>
</Tabs>

### Update a Pool

`update_pool` replaces the pool configuration. `image` is required on update. The warm buffer reconciles to the new settings; already-claimed sandboxes are unaffected.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    client.update_pool(
        pool_id=pool.pool_id,
        image="tensorlake/ubuntu-minimal",
        cpus=2.0,
        memory_mb=4096,
        warm_containers=5,
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    await client.updatePool(pool.poolId, {
      image: "tensorlake/ubuntu-minimal",
      cpus: 2.0,
      memoryMb: 4096,
      warmContainers: 5,
    });
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl -X PUT https://api.tensorlake.ai/sandbox-pools/<pool-id> \
      -H "Authorization: Bearer $TL_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "image": "tensorlake/ubuntu-minimal",
        "resources": {"cpus": 2.0, "memory_mb": 4096},
        "warm_containers": 5
      }'
    ```
  </Tab>
</Tabs>

### Delete a Pool

Deleting a pool tears down its warm containers. If sandboxes claimed from the pool are still active, the delete fails with `PoolInUseError` (HTTP `409`) — terminate the sandboxes first, or pass `force=true` over HTTP to terminate them along with the pool.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from tensorlake.sandbox import PoolInUseError

    try:
        client.delete_pool(pool.pool_id)
    except PoolInUseError:
        # Terminate active sandboxes first, then retry.
        raise
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    await client.deletePool(pool.poolId);
    // Throws PoolInUseError if sandboxes from the pool are still active.
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash theme={null}
    curl -X DELETE https://api.tensorlake.ai/sandbox-pools/<pool-id> \
      -H "Authorization: Bearer $TL_API_KEY"

    # Force-delete: also terminates active sandboxes from the pool
    curl -X DELETE "https://api.tensorlake.ai/sandbox-pools/<pool-id>?force=true" \
      -H "Authorization: Bearer $TL_API_KEY"
    ```
  </Tab>
</Tabs>

## Async

`AsyncSandboxClient` exposes the same pool methods (`create_pool`, `get_pool`, `list_pools`, `update_pool`, `delete_pool`, `claim`) as coroutines, and `AsyncSandbox.create(pool_id=...)` claims from a pool. See [Async](/sandboxes/async).

## Related Guides

<CardGroup cols={2}>
  <Card title="Lifecycle" icon="arrows-spin" href="/sandboxes/lifecycle">
    Create, suspend, resume, and terminate sandboxes.
  </Card>

  <Card title="Sandbox Images" icon="box" href="/sandboxes/images">
    Build the custom images your pools boot from.
  </Card>

  <Card title="Snapshots" icon="camera" href="/sandboxes/snapshots">
    Capture and restore sandbox state. Snapshot restores cold-boot and don't claim warm containers.
  </Card>

  <Card title="Networking" icon="network-wired" href="/sandboxes/networking">
    Egress policies you can set on a pool's template.
  </Card>
</CardGroup>
