Template builds can reuse cached file blobs, layers, and final artifacts when the builder inputs are compatible. Function installs are separate from template build cache. Deployed functions can build a reusable function artifact with nullspace functions deploy --rebuild; otherwise they fall back to running the configured install command inside each job run or service start when no custom template already contains those dependencies. Put heavy system packages or slow base dependency setup in a custom template when repeated install time is too expensive. Use skip_cache=True to bypass the whole build cache for one build:
build = Template.build(
    builder,
    name="agent-template",
    tags=["stable"],
    skip_cache=True,
)
import { NullspaceClient } from "@nullspace/sdk";

const client = new NullspaceClient();
const template = client.templates.builder().fromPythonImage("3.12");
const info = await template.build({
  name: "agent-template",
  tags: ["stable"],
  skipCache: true,
});
nullspace template build \
  --from-python-image 3.12 \
  --name agent-template \
  --tag stable \
  --skip-cache
# skip_cache is a top-level flag. Builds stream over SSE — see the API reference.
curl -N -X POST "${NULLSPACE_API_URL}/v1/templates/build" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "agent-template",
    "tags": ["stable"],
    "base_image": "python:3.12",
    "skip_cache": true
  }'
Use a builder cache boundary when only later steps should avoid cache reuse:
builder = (
    Template()
    .from_python_image("3.12")
    .pip_install(["requests"])
    .skip_cache()
    .run_cmd("date > /workspace/build-time.txt")
)
const builder = client.templates
  .builder()
  .fromPythonImage("3.12")
  .pipInstall(["requests"])
  .skipCache()
  .runCmd("date > /workspace/build-time.txt");
nullspace template build \
  --from-python-image 3.12 \
  --pip-install requests \
  --step-skip-cache \
  --run-cmd "date > /workspace/build-time.txt" \
  --name agent-template
# A cache boundary is a "skip_cache" step in the steps array. Builds stream
# over SSE — see the API reference for the full schema.
curl -N -X POST "${NULLSPACE_API_URL}/v1/templates/build" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "agent-template",
    "base_image": "python:3.12",
    "steps": [
      {"action": "pip_install", "packages": ["requests"]},
      {"action": "skip_cache"},
      {"action": "run", "command": "date > /workspace/build-time.txt"}
    ]
  }'
Force a copied file to upload even when a cached blob may exist:
builder = builder.copy("./model.bin", "/workspace/model.bin", force_upload=True)
builder.copy("./model.bin", "/workspace/model.bin", { forceUpload: true });
nullspace template build \
  --from-python-image 3.12 \
  --copy-src ./model.bin --copy-dst /workspace/model.bin --copy-force-upload \
  --name agent-template
Cache log entries expose a kind, status, reason, and subject when the backend reports them.
status = build.get_status(offset=0)
for entry in status.entries:
    if entry.kind == "cache":
        print(entry.cache_kind, entry.cache_status, entry.cache_reason)
Template warm pools are separate from build cache. A pool can only fill when the resolved template build and runtime artifact are available on compatible hosts. If artifact preparation blocks fill, pool status reports reasons such as artifact_not_ready or artifact_prewarm_failed instead of treating the condition as a generic cold-start failure.