> ## 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.

# Templates

> Build reusable machine environments from images, Dockerfiles, and builder steps.

Templates let you prepare dependencies once and launch machines from the
resulting environment.

## Build from Python

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

builder = (
    Template.from_python_image("3.12")
    .apt_install(["git", "curl"])
    .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="fastapi-app")
print(build.status)
```

The start command runs during template build before snapshotting. Machines
created from the template restore that ready running state instead of rerunning
the command at create time.

Warm pools use that same ready snapshot as their boot contract. Keep services
poolable by putting required startup envs in template runtime defaults and by
using readiness probes that succeed before snapshotting. Create-time envs,
volumes, cwd overrides, desktop settings, and per-create networking options are
not available to the prewarmed service boot path.

Create and wait for a template warm pool through the SDK:

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

pool = TemplateWarmPool.create(
    "team/fastapi-app:stable",
    name="fastapi-small",
    min_ready=2,
    max_ready=4,
    vcpus=2,
    memory_mb=1024,
)
pool.wait_until_ready(min_ready=2)
```

`Template.create_warm_pool(...)` is available when you already have a template
object. See [Template Warm Pools](../../templates/warm-pools) for checkout
modes, status fields, and drain behavior.

## Build-time and runtime envs

Nullspace deliberately separates env lifetime:

| Use case              | Nullspace method             | Visibility              |
| --------------------- | ---------------------------- | ----------------------- |
| Build-only values     | `set_build_envs({...})`      | Build steps only        |
| Runtime defaults      | `set_runtime_envs({...})`    | Persisted into machines |
| Create-time overrides | `Machine.create(envs={...})` | One machine             |

`set_runtime_envs()` values are also visible during later child template builds
as inherited defaults. `set_build_envs()` does not persist into launched
machines.

## Sources

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
Template.from_ubuntu_image("22.04")
Template.from_debian_image()
Template.from_node_image("20")
Template.from_bun_image("1.2")
Template.from_image("registry.example.com/team/app:1.0")
Template.from_dockerfile("./Dockerfile")
Template.from_dockerfile_content("FROM ubuntu:22.04\nRUN apt-get update")
Template.from_template("base")
```

For private registries, configure registry auth before build:

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
builder = Template.from_aws_registry(
    "123456789012.dkr.ecr.us-east-1.amazonaws.com/app:latest",
    access_key_id="...",
    secret_access_key="...",
    region="us-east-1",
)
builder = Template.from_gcp_registry(
    "gcr.io/project/app:latest",
    service_account_json="service-account.json",
)
```

Use `set_file_context()` for local Dockerfile-style copy contexts, and use
`to_json()` or `to_dockerfile()` to inspect the generated template before
building.

## Build options

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
build = Template.build(
    builder,
    name="fastapi-app",
    tags=["stable"],
    cpu_count=4,
    memory_mb=2048,
    skip_cache=True,
)
```

The same resource and cache options are available on
`Template.build_in_background()` and `builder.to_json(...)`.

## Build logs

Fetch build logs after starting a template build:

```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
nullspace template logs tb_123
nullspace template logs tb_123 --json
nullspace template logs tb_123 --since 2026-04-30T00:00:00Z
```

Native-backend Dockerfile instructions ignored with warning log entries:
`EXPOSE`, `VOLUME`, `ARG`, `LABEL`. BuildKit-backed Dockerfiles use BuildKit
failure and progress output instead.

Ignored-instruction warnings include the Dockerfile line number and appear in
the same structured build log stream used by `TemplateBuild.get_status()` and
`nullspace template logs`.

## Background builds

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
build = Template.build_in_background(builder, name="fastapi-app", tags=["next"])
connected = TemplateBuild.connect(build.build_id)
snapshot = connected.get_status(offset=0)
for entry in snapshot.entries:
    print(entry.kind, entry.message)

final = connected.wait_until_terminal(
    offset=snapshot.next_offset,
    on_log_entry=lambda entry: print(entry.message),
)
print(final.build.status)
```

Namespaces, reserved names, tags, aliases, and visibility are documented in
[Tags, Names, And Visibility](../../templates/tags-names).

Use `Template.list(fields=["id", "canonical_ref"])` and
`Template.get("team/template:tag", fields=["id", "canonical_ref"])` for compact
raw dictionaries when a control plane page only needs selected fields.

Concept: [Create](../../concepts/create). API reference:
[buildTemplate](../../api-reference), [startTemplateBuild](../../api-reference),
[getTemplateBuildStatus](../../api-reference), and [listTemplates](../../api-reference).
