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

# Template Warm Pools

> Keep ready capacity for a custom template and create machines from it with bounded fallback behavior.

Template warm pools keep tenant-owned ready capacity for a template. Use them
when you expect a burst of machines from the same prepared environment and the
template `start_cmd` plus readiness probes already produce the state each
machine should start from.

Warm pools do not preserve per-run mutable state. A checkout claims one ready
VM and turns it into a normal machine; it is not recycled back into the pool
after use.

Keeping a pool warm reserves runtime capacity. Treat `min_ready`, `max_ready`,
CPU, and memory as cost-bearing choices, and drain or delete pools when the
burst ends.

## Create A Pool

Build or identify a template first, then create a pool with public readiness
targets:

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
from nullspace import Template, TemplateWarmPool, wait_for_port

builder = (
    Template.from_python_image("3.12")
    .pip_install(["fastapi", "uvicorn"])
    .copy("./app.py", "/workspace/app.py")
    .set_workdir("/workspace")
    .set_start_cmd(
        "uvicorn app:app --host 0.0.0.0 --port 8080",
        readiness=wait_for_port(8080),
    )
)

build = Template.build(builder, name="review-api", tags=["stable"])

pool = TemplateWarmPool.create(
    build.canonical_ref,
    name="review-api-small",
    min_ready=2,
    max_ready=4,
    vcpus=2,
    memory_mb=1024,
    version_policy="pinned_build",
)
pool.wait_until_ready(min_ready=2)
print(pool.id)
```

If you already have a template object, `Template.create_warm_pool(...)` is a
convenience wrapper around `TemplateWarmPool.create(...)`.

The equivalent CLI flow uses `--json` for automation:

```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
nullspace template warm-pool create team/review-api:stable \
  --name review-api-small \
  --min-ready 2 \
  --max-ready 4 \
  --vcpus 2 \
  --memory 1024 \
  --json

nullspace template warm-pool wait twp_review_api_small --min-ready 2 --json
```

The HTTP API surface is `/v1/template-warm-pools` with create, list, get,
update, delete, status, enable, disable, drain, and reconcile operations.

Tenant pool placement scope is all-or-none. When a pool sets `host_pool_id` or
`cell_id`, both fields must be present and the resolved template must provide a
compatibility key. Partial scope is rejected so checkout cannot claim ready
inventory from a mismatched host class.

## Create From A Pool

Pass the explicit pool ID when creating machines:

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  from nullspace import Machine

  machine = Machine.create(
      template=build.canonical_ref,
      warm_pool=pool.id,
      warm_pool_mode="prefer",
      warm_pool_wait_ms=1500,
  )
  print(machine.get_info().warm_pool_checkout)
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace machine create \
    --template team/review-api:stable \
    --warm-pool twp_review_api_small \
    --warm-pool-mode prefer \
    --warm-pool-wait 1500 \
    --json
  ```
</CodeGroup>

`warm_pool_checkout` is present when create considered a warm pool. It reports
`source`, `hit`, `id`, and `mode` so callers can distinguish a ready checkout
from a cold fallback or explicit bypass.

## Checkout Modes

| Mode      | Behavior                                                                                          |
| --------- | ------------------------------------------------------------------------------------------------- |
| `prefer`  | Wait up to `warm_pool_wait_ms` for ready inventory, then fall back to cold create on a miss.      |
| `require` | Wait up to `warm_pool_wait_ms`, then fail with `warm_pool_unavailable` instead of cold creating.  |
| `bypass`  | Force cold create. This may omit `warm_pool` when the caller wants to skip pools for one request. |

Use `prefer` for general latency improvement and `require` when the work should
only run if ready capacity is available. In the CLI, pass
`--warm-pool-mode require` for the latter behavior.

## Poolable Shape

Template `start_cmd` and readiness are the pool startup contract. The command
runs during template build before snapshotting, and warm pools restore that
ready template state.

create-time envs, volume mounts, cwd overrides, desktop settings, custom
networking, non-destroy timeout policy, and auto-resume are not poolable
startup state. In `prefer` mode, unsupported create-time shape falls back to a
cold create. In `require` mode, it fails with `warm_pool_unavailable`.

snapshot restore, resume, fork, hibernate, and pause do not use template
warm-pool checkout. Use reusable snapshots or fork when you need mutable state
captured from a running machine, hibernate or auto-resume when one machine
should pause and continue later, and volumes when data must persist across
machine cleanup.

## Version Policy

`pinned_build` pools resolve the template ref to one build and continue filling
that build until updated.

`track_tag` pools follow a template tag. When the tag moves, the pool records a
new rollout generation, stops filling old ready or warming inventory, drains
old ready rows, and fills the new build. Machines already claimed from the old
build continue as normal user machines.

```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
nullspace template warm-pool create team/review-api:stable \
  --name review-api-stable \
  --min-ready 2 \
  --max-ready 4 \
  --version-policy track_tag \
  --track-tag stable \
  --json
```

## Status And Troubleshooting

Inspect status before a burst:

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  pool = TemplateWarmPool.get("twp_review_api_small")
  info = pool.get_info()
  print(info.status.ready, info.status.warming, info.degraded_reason)
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace template warm-pool get twp_review_api_small --json
  nullspace template warm-pool list --template team/review-api:stable --status ready --json
  ```
</CodeGroup>

Status counts are `target`, `ready`, `warming`, `claimed`, `draining`,
`failed`, `expired`, and `unavailable`.

Common degraded reasons:

| Reason                       | Meaning                                                              |
| ---------------------------- | -------------------------------------------------------------------- |
| `no_eligible_hosts`          | No compatible runtime host can fill the pool.                        |
| `artifact_not_ready`         | The resolved template artifact is not ready on an eligible host yet. |
| `artifact_prewarm_failed`    | Preparing the template artifact for pool fill failed.                |
| `quota_exceeded`             | Warm capacity is blocked by an account or deployment quota.          |
| `template_build_unavailable` | The resolved template build or artifact is no longer usable.         |
| `controller_disabled`        | Pool reconciliation is disabled by the deployment.                   |
| `drain_active`               | The pool is draining and will not refill ready capacity.             |

If a burst must not cold start, use `require` and handle
`warm_pool_unavailable` explicitly. If cold fallback is acceptable, use
`prefer` and inspect `warm_pool_checkout.source` after create.

## Drain And Delete

Drain a pool when the burst ends or before replacing it:

```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
nullspace template warm-pool drain twp_review_api_small --json
nullspace template warm-pool delete twp_review_api_small --json
```

Draining stops refill and releases ready inventory over the normal controller
budget. Deleting a pool requests drain; it does not destroy machines that were
already checked out.

## Related

* [Start & ready commands](./start-ready)
* [Template caching](./caching)
* [Template warm-pool example](../examples/template-warm-pools)
* [Create, connect, and list machines](../machines/create-connect-list)
* [CLI template commands](../cli/manage-templates)
* [Python SDK templates](../guides/python-sdk/templates)
