Skip to main content

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 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.
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")
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().
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,
})
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 12, 2026