#Template

A Template is the blueprint for creating Sandboxes. It defines the container image, resource limits, warm pool size, and default network policy. Every Sandbox is created from a Template.

Creating, updating, and deleting team-owned templates requires team admin permissions. developer and builder roles can read templates, and builder is typically used for registry push workflows rather than template management.

Template Types#

Sandbox0 has two categories of templates:

TypeDescriptionVisibility
BuiltinSystem-provided templates managed by the platform operatorPublic — visible to all teams
CustomTemplates created and owned by your teamPrivate — visible to your team only (configurable)

Builtin templates use curated public images and are ready to use immediately. Custom templates let you bring your own image, fine-tune resources, mount volumes, configure environment variables, and define default network policy.


Custom Template Or Rootfs Snapshot#

You do not need a custom template for every initialized environment. If the base image, resources, network policy, and mount declarations already fit, you can claim a sandbox from a builtin template, install dependencies or clone repositories inside the writable root filesystem, pause it, create a rootfs snapshot, then claim future sandboxes with that snapshot_id.

This is useful for dependency-heavy agent workspaces:

  1. claim a sandbox from a platform-owned builtin template such as default or dins
  2. install packages, populate caches, clone repositories, or write tool configuration
  3. pause the sandbox and wait for status to become paused
  4. create a named rootfs snapshot for the initialized state
  5. claim each task sandbox with the same template and snapshot_id

For platform-owned builtin templates, the operator manages the warm pool. That lets teams reuse warm builtin capacity and store only the initialized rootfs state for their own dependency set instead of maintaining a separate custom template pool for each variation.

NeedPrefer
Different base image, resource envelope, default environment, mount paths, network defaults, or privileged runtime fieldsCustom template
User-space dependencies, repository checkout, package cache, generated files, or per-project tool configuration on an existing base imageBuiltin template plus rootfs snapshot and claim with snapshot_id
Data that must outlive sandbox identity, be mounted by multiple sandboxes, or be accessed through direct storage APIsSandbox Volume

Rootfs snapshots do not create template IDs and do not appear in s0 template list. Claiming with snapshot_id creates a new running sandbox from the selected rootfs snapshot while the requested template still controls image, resources, mounts, services, and network defaults. Restore remains useful for rolling back an existing paused sandbox, and fork remains useful when you specifically need a paused child sandbox. See Snapshot And Restore for the paused-state requirements and API workflow, or read Initialize Once, Claim Many for the custom-rootfs pattern.


Create Template#

Create a custom template for your team. The template spec is defined in a YAML file.

CLI examples assume you already ran s0 auth login and selected the correct current team.

POST

/api/v1/templates

Request Body#

FieldTypeDescription
template_idstringUnique identifier for the template (e.g., my-python-env)
specobjectFull template specification

Template IDs must be unique within your team. Once created, the ID cannot be changed — create a new template if you need a different ID.

Example spec file (template.yaml):

yaml
spec: mainContainer: image: python:3.12-slim resources: cpu: "1" memory: 4Gi ephemeralStorage: 8Gi pool: minIdle: 2 maxIdle: 10
go
tpl, err := client.CreateTemplate(ctx, apispec.TemplateCreateRequest{ TemplateID: "my-python-env", Spec: apispec.SandboxTemplateSpec{ MainContainer: apispec.NewOptContainerSpec(apispec.ContainerSpec{ Image: "python:3.12-slim", Resources: apispec.ResourceQuota{ CPU: apispec.NewOptString("1"), Memory: apispec.NewOptString("4Gi"), EphemeralStorage: apispec.NewOptString("8Gi"), }, }), Pool: apispec.NewOptPoolStrategy(apispec.PoolStrategy{ MinIdle: 2, MaxIdle: 10, }), }, }) if err != nil { log.Fatal(err) } fmt.Printf("Template created: %s\n", tpl.TemplateID)

Get Template#

Retrieve a specific template by ID. Your team can access both its own templates and builtin templates.

GET

/api/v1/templates/{id}

go
tpl, err = client.GetTemplate(ctx, "my-python-env") if err != nil { log.Fatal(err) } fmt.Printf("Template: %s (scope: %s)\n", tpl.TemplateID, tpl.Scope)

List Templates#

List all templates visible to your team — including your team's custom templates and all public builtin templates.

GET

/api/v1/templates

go
templates, err := client.ListTemplate(ctx) if err != nil { log.Fatal(err) } for _, tpl := range templates { display, _ := tpl.Spec.DisplayName.Get() fmt.Printf("- %s (%s) scope=%s\n", tpl.TemplateID, display, tpl.Scope) }

Update Template#

Update the spec of an existing custom template. The update triggers a reconciliation across all clusters — running sandboxes are not affected.

PUT

/api/v1/templates/{id}

Updating a template does not affect already-running Sandboxes. New Sandboxes claimed after the update will use the new spec. Idle pods in the pre-warm pool are recycled and replaced with pods matching the new spec.

go
tpl, err = client.UpdateTemplate(ctx, "my-python-env", apispec.TemplateUpdateRequest{ Spec: apispec.SandboxTemplateSpec{ MainContainer: apispec.NewOptContainerSpec(apispec.ContainerSpec{ Image: "python:3.12-slim", Resources: apispec.ResourceQuota{ CPU: apispec.NewOptString("2"), Memory: apispec.NewOptString("8Gi"), EphemeralStorage: apispec.NewOptString("8Gi"), }, }), Pool: apispec.NewOptPoolStrategy(apispec.PoolStrategy{ MinIdle: 3, MaxIdle: 10, }), }, }) if err != nil { log.Fatal(err) } fmt.Printf("Template updated: %s\n", tpl.TemplateID)

Delete Template#

Delete a custom template. All cluster allocations for the template are cleaned up via reconciliation.

DELETE

/api/v1/templates/{id}

Deleting a template does not terminate running Sandboxes created from it, but no new Sandboxes can be created from the deleted template.

go
_, err = client.DeleteTemplate(ctx, "my-python-env") if err != nil { log.Fatal(err) } fmt.Println("Template deleted")

Next Steps#

Custom Images

Build and reference custom container images for sandbox templates.

Warm Pool

Use warm pools to reduce startup latency for common templates.

Snapshot And Restore

Reuse initialized rootfs state without creating another template.

Initialize Once, Claim Many

Customize a builtin template with rootfs snapshots and claim-time snapshot IDs.