# Concepts - Documentation

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown is available with `Accept: text/markdown` and `.md` URL variants.

Source: /docs/guides/sandbox-template-concepts

# Concepts

##

[​](#how-it-works)

How it works

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

- Resolve the template source such as a standard base image, an existing image, a Dockerfile, or another template.

- Apply template instructions such as `runCmd`, `copy`, `makeDir`, `setEnvs`, and package-install helpers.

- If configured, start the template start command.

- Wait until the [ready command](/docs/guides/sandbox-template-authoring#start--ready-commands) succeeds.

- 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)

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.

JavaScript & TypeScript

Python

```
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")
```

```
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")
)
```

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

##

[​](#caching)

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()`.

JavaScript & TypeScript

Python

```
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,
})
```

```
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,
)
```

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.

Last modified on June 24, 2026
