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

# Concepts

## How it works

At a high level, a template build works like this:

1. Resolve the template source such as a standard base image, an existing image, a Dockerfile, or another template.
2. Apply template instructions such as `runCmd`, `copy`, `makeDir`, `setEnvs`, and package-install helpers.
3. If configured, start the template start command.
4. Wait until the [ready command](/guides/sandbox-template-authoring#start--ready-commands) succeeds.
5. Save the prepared environment as a reusable template.

The build produces a `templateId` / `template_id` and a `buildId` / `build_id`. Use the template ID later with `Sandbox.create(...)`.

## User and workdir

Templates can set the default Linux user and working directory used by later build steps and by the final environment.

Use `setUser(...)` / `set_user(...)` when build commands must run as a specific user. Use `setWorkdir(...)` / `set_workdir(...)` when later commands and copied files should resolve relative to a specific directory.

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

  const template = Template()
    .fromUbuntuImage("24.04")
    .setUser("root")
    .setWorkdir("/app")
    .runCmd("apt-get update && apt-get install -y curl")
    .copy("package.json", "/app/package.json")
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.core import Template

  template = (
      Template()
      .from_ubuntu_image("24.04")
      .set_user("root")
      .set_workdir("/app")
      .run_cmd("apt-get update && apt-get install -y curl")
      .copy("package.json", "/app/package.json")
  )
  ```
</CodeGroup>

If you do not set these values, the sandbox uses the defaults from the selected base image.

## Caching

Template builds cache previously completed layers so repeated builds do not have to rerun every instruction.

This is usually what you want for fast iteration. When you need a fully fresh build, disable cache for the whole build with `skipCache: true` / `skip_cache=True`, or mark the template chain with `skipCache()` / `skip_cache()`.

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

  const template = Template()
    .fromPythonImage("3.12")
    .skipCache()
    .runCmd("pip install -U pip")

  const build = await Template.build(template, "my-template-no-cache", {
    skipCache: true,
  })
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.core import Template

  template = (
      Template()
      .from_python_image("3.12")
      .skip_cache()
      .run_cmd("pip install -U pip")
  )

  build = Template.build(
      template,
      "my-template-no-cache",
      skip_cache=True,
  )
  ```
</CodeGroup>

Use cache-busting intentionally. It slows builds down and should normally be reserved for dependency refreshes, debugging, or changes to inputs that are not visible from the template definition alone.
