# Authoring - 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-authoring

# Authoring

##

[​](#base-image)

Base image

Every template starts from a source environment. The SDK supports several entry points depending on how much control you need.

- `fromPythonImage(...)` / `from_python_image(...)` for a standard Python runtime

- `fromUbuntuImage(...)` / `from_ubuntu_image(...)` or `fromDebianImage(...)` / `from_debian_image(...)` for a standard Linux base

- `fromNodeImage(...)` / `from_node_image(...)` and `fromBunImage(...)` / `from_bun_image(...)` for language-specific bases

- `fromImage(...)` / `from_image(...)` for an arbitrary container image

- `fromDockerfile(...)` / `from_dockerfile(...)` when your Dockerfile is already the source of truth

- `fromBaseImage()` / `from_base_image()` to start from the platform default base

- `fromTemplate(...)` / `from_template(...)` to layer on top of another template

`fromPythonImage("3.12")` and `from_python_image("3.12")` are equivalent to starting from:

Dockerfile

```
FROM python:3.12
```

##

[​](#private-registries)

Private registries

If your base image lives in a private registry, pass credentials when defining the template source.
The JS and Python SDKs support:

- generic registry credentials with username and password

- AWS registry credentials

- GCP registry credentials

- Huawei Cloud registry credentials

Generic private registry example:

JavaScript & TypeScript

Python

```
import { Template } from "novita-sandbox"

const template = Template().fromRegistry(
"registry.example.com/team/myimage:latest",
{
username: process.env.REGISTRY_USERNAME,
password: process.env.REGISTRY_PASSWORD,
}
)

const build = await Template.build(template, "my-private-image-template")
console.log(build.templateId)
```

```
import os

from novita_sandbox.core import Template

template = Template().from_registry(
"registry.example.com/team/myimage:latest",
username=os.environ.get("REGISTRY_USERNAME"),
password=os.environ.get("REGISTRY_PASSWORD"),
)

build = Template.build(template, "my-private-image-template")
print(build.template_id)
```

##

[​](#defining-template)

Defining template

The builder API lets you compose the final environment directly in code. Common definition steps include:

- `runCmd(...)` / `run_cmd(...)` to install packages or run provisioning commands

- `copy(...)` to include local files

- `makeDir(...)`, `remove(...)`, `rename(...)`, and `makeSymlink(...)` for filesystem shaping

- `setEnvs(...)` / `set_envs(...)` for environment variables

- `pipInstall(...)`, `npmInstall(...)`, `bunInstall(...)`, and `aptInstall(...)` for package setup

- `gitClone(...)` / `git_clone(...)` to bring code into the image

Example:

JavaScript & TypeScript

Python

```
import { Template } from "novita-sandbox"

const template = Template()
.fromPythonImage("3.12")
.setWorkdir("/app")
.setEnvs({
APP_ENV: "production",
PORT: "8000",
})
.runCmd("pip install fastapi uvicorn")
.copy("app.py", "/app/app.py")
```

```
from novita_sandbox.core import Template

template = (
Template()
.from_python_image("3.12")
.set_workdir("/app")
.set_envs(
{
"APP_ENV": "production",
"PORT": "8000",
}
)
.run_cmd("pip install fastapi uvicorn")
.copy("app.py", "/app/app.py")
)
```

##

[​](#start-&-ready-commands)

Start & ready commands

Use a start command when the template should boot a long-running service during the build result, and use a ready command to define when that service is considered healthy.
This is useful for web apps, API servers, background workers, and any template that should already be initialized when a sandbox starts.

JavaScript & TypeScript

Python

```
import { Template } from "novita-sandbox"

const template = Template()
.fromPythonImage("3.12")
.runCmd("pip install fastapi uvicorn")
.copy("app.py", "/home/user/app.py")
.setStartCmd(
"uvicorn app:app --host 0.0.0.0 --port 8000",
"python - You can also configure readiness separately with `setReadyCmd(...)` / `set_ready_cmd(...)`.

Last modified on June 5, 2026
