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

# Build Template

A **template** is the blueprint a sandbox is created from — it defines the base image, installed packages, files, environment, and the commands that run at startup. Every sandbox is spawned from a template, so building a template is how you produce a reusable, ready-to-run environment.

Templates are conceptually close to container images: a template is **built from a Docker image**, and the build process is **similar to writing a Dockerfile** — you start from a base image and layer instructions on top. The difference is where and how you express those instructions.

|                       | Template                                                                                       | Dockerfile / Docker image                         |
| --------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| Starts from           | A **Docker image** (e.g. `fromImage('python:3.12')`) or another template                       | A base image via `FROM`                           |
| How steps are written | SDK builder calls — `runCmd`, `copy`, `setEnvs`, … (like Dockerfile instructions, but in code) | Dockerfile instructions — `RUN`, `COPY`, `ENV`, … |
| Extra config          | Also captures sandbox settings: start command, ready command, CPU / memory                     | Only the image contents                           |
| Result                | A `templateId` you pass to `sandbox.create(...)`                                               | An image you run as a container                   |

In short: a template **starts from a Docker image**. Building one feels similar to authoring a Dockerfile, but you describe the steps with the SDK (`fromImage`, `runCmd`, `copy`, `setEnvs`, …) instead of a `Dockerfile`. The output is a `templateId` that Novita uses to launch sandboxes quickly.

***

## Build

Once a template definition is ready, use `novita.template.build(...)` to build it.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Novita } from 'novita-sandbox'

  const novita = new Novita()
  const template = novita.template.new().fromImage('python:3.12')

  const build = await novita.template.build(template, 'my-python-template', {
    cpuCount: 2,
    memoryMB: 1024,
  })

  const sandbox = await novita.sandbox.create(build.templateId)
  console.log(sandbox.sandboxId)

  await sandbox.kill()
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox import Novita

  novita = Novita()
  template = novita.template.new().from_image("python:3.12")

  build = novita.template.build(
      template,
      "my-python-template",
      cpu_count=2,
      memory_mb=1024,
  )

  sandbox = novita.sandbox.create(build.template_id)
  print(sandbox.sandbox_id)

  sandbox.kill()
  ```

  ```bash CLI icon="terminal" theme={"system"}
  # Build a Dockerfile into a Sandbox template (alias: template ct)
  # Reads ./novita.Dockerfile (or Dockerfile) in the root directory by default
  novita-sandbox-cli template create my-python-template

  # Specify a Dockerfile, resources, and start command
  novita-sandbox-cli template create my-python-template \
    --dockerfile ./novita.Dockerfile \
    --cpu-count 2 \
    --memory-mb 1024 \
    --cmd "python app.py"
  ```
</CodeGroup>

## Names

Every build needs a template name. Keep names stable for a logical template family. The returned template ID is the immutable build output you use at runtime.

## Base Image

A template definition always starts by choosing a base image (or an existing template) with one of the `from*` methods.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Novita } from 'novita-sandbox'

  const novita = new Novita()

  // Novita's default base image
  const base = novita.template.new().fromBaseImage()

  // A specific language image
  const python = novita.template.new().fromPythonImage('3.12')
  const ubuntu = novita.template.new().fromUbuntuImage('24.04')

  // A custom image (optionally with private registry credentials)
  const custom = novita.template
    .new()
    .fromImage('myregistry.com/myimage:latest', {
      username: 'user',
      password: 'pass',
    })
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox import Novita

  novita = Novita()

  # Novita's default base image
  base = novita.template.new().from_base_image()

  # A specific language image
  python = novita.template.new().from_python_image("3.12")
  ubuntu = novita.template.new().from_ubuntu_image("24.04")

  # A custom image (optionally with private registry credentials)
  custom = novita.template.new().from_image(
      "myregistry.com/myimage:latest",
      credentials={"username": "user", "password": "pass"},
  )
  ```
</CodeGroup>

## User and Workdir

After choosing a base image, you can control which user subsequent build steps run as and which directory they run in.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Novita } from 'novita-sandbox'

  const novita = new Novita()
  const template = novita.template
    .new()
    .fromUbuntuImage('24.04')
    .setUser('root')
    .aptInstall(['git'])
    .setUser('user')
    .setWorkdir('/home/user/app')
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox import Novita

  novita = Novita()
  template = (
      novita.template.new()
      .from_ubuntu_image("24.04")
      .set_user("root")
      .apt_install(["git"])
      .set_user("user")
      .set_workdir("/home/user/app")
  )
  ```
</CodeGroup>

## Tags & versioning

Tags let you label builds for release management without changing the underlying template name.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Novita } from 'novita-sandbox'

  const novita = new Novita()
  const template = novita.template.new().fromPythonImage('3.12')

  const build = await novita.template.build(template, 'agent-runtime-base', {
    tags: ['v1.0.0', 'latest'],
  })

  await novita.template.assignTags('agent-runtime-base:v1.0.0', 'production')

  const tags = await novita.template.getTags(build.templateId)
  console.log(tags)
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox import Novita

  novita = Novita()
  template = novita.template.new().from_python_image("3.12")

  build = novita.template.build(
      template,
      "agent-runtime-base",
      tags=["v1.0.0", "latest"],
  )

  novita.template.assign_tags("agent-runtime-base:v1.0.0", "production")

  tags = novita.template.get_tags(build.template_id)
  print(tags)
  ```
</CodeGroup>

## Logging

Build logs help you inspect provisioning progress and diagnose failures.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Novita } from 'novita-sandbox'

  const novita = new Novita()
  const template = novita.template.new().fromPythonImage('3.12')

  const build = await novita.template.build(template, 'my-logged-template')
  console.log(build.buildId)
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox import Novita

  novita = Novita()
  template = novita.template.new().from_python_image("3.12")

  build = novita.template.build(template, "my-logged-template")
  print(build.build_id)
  ```
</CodeGroup>

## Error handling

Template builds can fail for several common reasons:

* invalid credentials for a private registry
* package install failures inside `runCmd(...)` / `run_cmd(...)`
* a start command that exits unexpectedly
* a ready command that never succeeds
* CPU and memory settings that do not satisfy platform limits
