Templates capture setup once so every machine can start from a ready environment.
Python SDK
TypeScript SDK
CLI
HTTP API
from nullspace import Machine, Template, default_build_logger
builder = (
Template ()
. from_python_image ( "3.12" )
. apt_install ([ "git" , "curl" ])
. pip_install ([ "fastapi" , "uvicorn" ])
. copy ( "./app.py" , "/workspace/app.py" )
. set_workdir ( "/workspace" )
)
build = Template. build (
builder,
name = "fastapi-agent" ,
tags = [ "stable" ],
on_log_entry = default_build_logger (),
)
with Machine. create ( template = build.canonical_ref) as machine:
result = machine.commands. run ( "python3 --version" , shell = True )
print (result.stdout)
import { NullspaceClient } from "@nullspace/sdk" ;
const client = new NullspaceClient ();
const template = await client . templates
. builder ()
. fromPythonImage ( "3.12" )
. aptInstall ([ "git" , "curl" ])
. pipInstall ([ "fastapi" , "uvicorn" ])
. copy ( "./app.py" , "/workspace/app.py" )
. setWorkdir ( "/workspace" )
. build ({
name : "fastapi-agent" ,
tags : [ "stable" ],
onLogEntry : ( entry ) => console . log ( entry . message ),
});
await using machine = await client . machines . create ({
template : ` ${ template . name } :stable` ,
});
const result = await machine . commands . run ( "python3 --version" , { shell : true });
console . log ( result . stdout );
nullspace template build \
--from-python-image 3.12 \
--apt-install git,curl \
--pip-install fastapi,uvicorn \
--copy-src ./app.py --copy-dst /workspace/app.py \
--set-workdir /workspace \
--name fastapi-agent \
--tag stable
nullspace machine create --template fastapi-agent:stable
# Template builds stream structured logs over SSE; the request body is large.
# See the API reference for the full CreateTemplateRequest schema.
curl -N -X POST " ${ NULLSPACE_API_URL } /v1/templates/build" \
-H "Authorization: Bearer ${ NULLSPACE_API_KEY } " \
-H "Content-Type: application/json" \
-d '{
"name": "fastapi-agent",
"tags": ["stable"],
"base_image": "python:3.12",
"steps": [
{"action": "apt_install", "packages": ["git", "curl"]},
{"action": "pip_install", "packages": ["fastapi", "uvicorn"]},
{"action": "workdir", "path": "/workspace"}
]
}'
Use Template.build_in_background() when a build should continue while your
client disconnects or polls progress later.
build = Template. build_in_background (builder, name = "fastapi-agent" , tags = [ "next" ])
finished = build. wait_until_terminal ()
print (finished.build.status)
nullspace template build \
--from-python-image 3.12 \
--name fastapi-agent \
--tag next \
--background
nullspace template wait tb_... --poll-interval-ms 500
# POST /v1/templates/builds accepts the same CreateTemplateRequest body and
# returns a build handle to poll with GET /v1/templates/builds/{build_id}.
curl -X POST " ${ NULLSPACE_API_URL } /v1/templates/builds" \
-H "Authorization: Bearer ${ NULLSPACE_API_KEY } " \
-H "Content-Type: application/json" \
-d '{
"name": "fastapi-agent",
"tags": ["next"],
"base_image": "python:3.12"
}'
The TypeScript SDK builds synchronously over the SSE stream; for
background builds and polling, use the Python SDK, CLI, or HTTP API.
See the API reference for the full template build request
schema and background-build polling.