Templates
Define what a sandbox starts from, and build versions of it.
A template is what a sandbox starts from. Building it produces a version, and a version holds everything a sandbox needs: the image, the size it gets by default, and the environment inside it. A sandbox created from the template starts from one of those versions.
Set your org and project with tektona ctx before you begin.
Naming a template
A template reference carries a scope and a name:
| Reference | What it means |
|---|---|
go-dev | A template in your current project |
project/go-dev | The same thing, written out |
org/go-dev | A template your organization owns |
tektona/sandbox-base | A template Tektona provides |
Add :<tag> to pick a tag: go-dev:stable. No tag means the default tag.
The scope always comes from your CLI context. A manifest never carries an org or a project, so you can commit one and it works in every project.
An image, and nothing else
You have an image — one you built, or a public one — and you want a sandbox running it. That is two commands, and no file:
tektona template create go-dev --image ghcr.io/tektona-ai/sandbox-base:0.5.0 --default-cpu 4 --default-memory 8
tektona sandbox create go-devThe first waits, and prints the build's steps and log as they arrive. It exits
non-zero when the build fails. Its version takes the default tag, which is
what the bare go-dev in the second command resolves.
build run creates the template too when it does not exist, so the command to
rebuild from a newer image is the command you already know. It moves no tag on
its own, whichever it is doing, so name one to promote what it builds:
tektona template build run go-dev --image ghcr.io/tektona-ai/sandbox-base:0.6.0 --tag defaultOnly create gives a tag without being asked, and only to the template it is
creating. A build never moves a tag it was not given.
The flags cover this case. Everything past it — a bigger build machine, an environment, a pinned user — lives in a manifest.
The manifest
A manifest is the complete surface. init writes one to start from:
tektona template init go-dev
tektona template init go-dev --image ubuntu:24.04That writes ./go-dev.template.tektona.yaml, named after the template, so a
repository holds one file per template. Give it a path to write somewhere else,
and --force to overwrite a file that is already there.
init takes the name alone, not a reference: a manifest carries no scope, so
tektona template init org/go-dev is refused.
# yaml-language-server: $schema=https://schemas.tektona.ai/sandbox-template/v1.json
apiVersion: tektona.ai/v1
kind: SandboxTemplate
metadata:
name: go-dev
displayName: Go development
spec:
build: # what the version is built from
image: ghcr.io/tektona-ai/sandbox-base:0.5.0
resources: # the size of the sandbox that runs the build
cpu: 8
memory: 16
sandbox: # what a sandbox made from the version gets
defaultResources:
cpu: 4
memory: 8
disk: 20
env:
- name: NODE_ENV
value: development
user: dev
workdir: /workspaceThe first line points your editor at the schema. An editor that runs
yaml-language-server then completes these keys and marks mistakes as you type.
One rule decides what an edit costs. metadata changes nothing about a
sandbox, so it applies on its own. Everything under spec belongs to a version,
and only a build mints one:
tektona template update -f go-dev.template.tektona.yaml # applies metadata, builds nothing
tektona template build run -f go-dev.template.tektona.yaml # applies metadata, then buildsA resize therefore costs a build, the same as a new base image does. The build
names the image again, from the file or from --image, and a pull of an image
the platform already has is fast.
build -f creates the template when it does not exist yet. update -f reads
the same file and applies its metadata block only; it says so when the file
carries a spec.
Commands
| Command | What it does |
|---|---|
tektona template init <name> [path] | Write a template manifest file. --image writes the base image into it |
tektona template create <template-ref> | Create a template, and optionally build its first version. --image is what builds one |
tektona template update <template-ref> | Change a template's details. Builds nothing |
tektona template build run <template-ref> | Build a version, and wait for it |
tektona template ls | List the templates you can use, with the versions, tags, sandboxes and storage each holds |
tektona template get <template-ref> | Show one template: what it is called, what it holds and what it costs |
tektona template version ls <template-ref> | List a template's versions, newest first |
tektona template version get <template-ref> <version-id> | Show one version: what it was built from, what a sandbox made from it gets, and whether a create through it works |
tektona template version archive <template-ref> <version-id> | Refuse a create from one version. activate allows it again |
tektona template version rm <template-ref> <version-id> | Delete one version, and every tag pointing at it |
tektona template version prune <template-ref> | Delete every version of a template that no tag points at and no sandbox records |
tektona template tag ls <template-ref> | List a template's tags, with the version each points at |
tektona template tag get <template-ref> <tag> | Show one tag and the version under it, and whether a create through it works |
tektona template tag set <template-ref> <tag> <version-id> | Point a tag at a version, creating the tag when it does not exist |
tektona template tag rm <template-ref> <tag> | Delete a tag. The version it pointed at stays |
tektona template archive <template-ref> | Refuse a create from a template |
tektona template activate <template-ref> | Put it back |
tektona template rm <template-ref> | Delete a template, its versions, their tags and its builds. Asks first when it has build records; --yes skips. Refused while a sandbox uses it. Alias delete |
tektona template build ls [<template-ref>] | List builds in the current scope, narrowed to a template when you name one |
tektona template build get <build-id> | Show one build: what it built from, what it produced and how it ended |
tektona template build logs <build-id> | Print a build's steps and log. -f waits for one still running. --tail N prints only the last N lines, --head N only the first N, and --tail N -f follows from where the tail ended |
tektona template build cancel <build-id> | Cancel a running build. Aliases stop and abort |
JSON output
ls, info and logs take -o json, and all three print what the API
returned.
ls prints the templates as objects, not the summary the table shows. logs
prints one JSON document per line while it follows a build — {"line": ...} for
a log line, {"step": ...} when a step changes, and one {"build": ...} at the
end. Read it a line at a time; the last line carries the version.
Flags
Every flag names the manifest block it writes, so there is nothing to remember
about where a value lands. --image is the exception, and short because it is
the one flag nearly every build passes.
| Flag | Writes |
|---|---|
--default-cpu / --default-memory / --default-disk | spec.sandbox.defaultResources |
--sandbox-env / --sandbox-user / --sandbox-workdir | spec.sandbox |
-i, --image | spec.build.image |
--build-cpu / --build-memory / --build-disk | spec.build.resources |
--run | spec.build.steps — one command per flag, repeatable |
--build-env / --build-user / --build-workdir | spec.build |
--build-egress-network-policy / --build-egress-proxy-profile | spec.build |
--display-name / --description | metadata |
--tag | The tag this build moves on success. Omitted, no tag moves |
-f, --file | Read a manifest instead of flags |
--sandbox-env and --build-env both take KEY=VAL and repeat.
--sandbox-env reaches the sandbox; --build-env reaches the commands and
nothing else.
user, workdir and env are keys of both blocks, and the block is the whole
difference: under spec.build they apply to the commands, and under
spec.sandbox to a sandbox made from the version. The flags carry the block, so
--build-user and --sandbox-user can never be confused.
Pass no --build-user and the commands run as the image's own user, in its
WORKDIR. Ubuntu and Alpine declare no user, so their commands run as root. An
image that declares one needs --build-user root to install packages.
Every flag above writes a spec block, so create and build take them and
update does not. update takes --display-name, --description and -f.
The flags cover the common case. Anything they do not reach lives in a
manifest — a per-step user or workdir, and the shell the steps run through.
A manifest and the flags do not mix
With -f, the file owns every value it can carry — metadata and both spec
blocks. Pass a flag that writes one of them as well and the command refuses it
by name, rather than applying one input and dropping the other. Edit the file,
or drop -f and pass every flag.
--image is the one exception, and it overrides the file: a base image is what
varies between builds of one manifest. --tag and --detach are not part of a
manifest, so they combine with -f freely.
tektona template build run --file go-dev.template.tektona.yaml --image ubuntu:22.04 --tag 22.04Versions and tags
Every build produces a version, and a version never changes. A tag is a name that points at one, and a build moves the tag it names:
tektona template build run go-dev --tag stable
tektona template build run go-dev:stable # the same thing
tektona sandbox create go-dev:stablecreate reads a tag the same way, because it mints a version too. Both
commands take --tag, and --tag wins when a reference names one as well.
A build with no --tag moves no tag. That is how you build an image, test
it, and only then decide it is good. The version is reached by its id, which the
build prints, and tektona template version ls lists:
tektona template build run go-dev # no tag moves
tektona template version ls go-dev --tagged=false # the versions no tag points at
tektona sandbox create go-dev --template-version 01JABCDEF0123456789ABCDEFG--tagged takes three states. Left out, version ls lists every version.
--tagged lists the versions a tag points at, and --tagged=false lists the
rest.
Once you decide a version is good, move the tag onto it. This runs no build:
A template can carry at most 500 tags, but tag set still moves an existing
tag at this limit.
tektona template tag ls go-dev
tektona template tag set go-dev stable 01JABCDEF0123456789ABCDEFG
tektona template tag rm go-dev oldName the template, then the tag. go-dev:stable is how you read a tag —
sandbox create and build run resolve that form — and these commands write
one, so the tag is an argument of its own.
The version may be an older one, which is how you roll back. Deleting a tag leaves its version in place, still reachable by its id.
Only build run and create take a tag in the reference, because both mint a
version for the tag to land on. Every other command names a template, and
refuses a reference carrying a tag rather than ignoring it.
Pinning a version fixes everything about it, the size included: a version holds
its own spec.sandbox, so two versions of one template can have different
defaults.
Sizes
spec.sandbox.defaultResources is what a sandbox made from the version gets.
spec.build.resources is the size of the sandbox that runs the build. They are
two different machines.
A create overrides the version's defaults one field at a time:
tektona sandbox create go-dev --cpu 8That sandbox gets 8 cores and keeps the version's memory and disk.
What a sandbox started from
A sandbox records the reference it asked for and the version it got. tektona sandbox get prints all three:
Template
Reference go-dev
Tag stable
Version 01JABCDEF0123456789ABCDEFGThe version is the one the create resolved. A tag that moves to a newer version later does not change it, so this still says what the sandbox runs.
A create that pinned a version id asked for no tag, and the tag reads as a dash.
A create that named no tag asked for default, and the tag says so.
tektona sandbox ls --wide adds a TEMPLATE column with the same reference.
-o json carries reference, name, scope, tag and version_id on both
commands.
Archiving
Archiving refuses a create from a template. The create is refused,
sandboxes already running on it keep running, and activate reverses it.
Your archived template stays in tektona template ls, with archived in its
STATUS column, so you can find it and activate it. An archived tektona/* template leaves the
listing: it is Tektona's, so you can neither activate it nor create from it. You
still read it with tektona template get tektona/<name>.
tektona template archive go-dev
tektona template activate go-devArchive one version instead, and the template stays usable:
tektona template version archive go-dev 01JABCDEF0123456789ABCDEFG
tektona template version activate go-dev 01JABCDEF0123456789ABCDEFGA tag pointing at the version does not stop the archive. The tag stays where it is and keeps naming the version. A sandbox create through that tag fails while the version is archived, and activating the version makes the tag work again.
To remove a version outright, tektona template version rm deletes it and
every tag pointing at it. A sandbox that records the version blocks the delete,
a paused or stopped one included, and the refusal counts them.
To clear a whole template at once, tektona template version prune removes
every version of it that nothing uses:
tektona template version prune go-devA version is unused when no tag points at it and no sandbox records it. The
command lists what it removes and asks first; --yes skips the question. It
never removes a version a tag points at, and never one a sandbox records — a
paused sandbox counts, one whose teardown has not finished counts, and so does
every fork. It reports how many it removed, and how many it kept for each
reason.
A create resolves the template before the version, so an archived template
refuses a create through every version below it. Those versions still read
active, so version ls, version get and tag get print the effective
answer beside the state: refused: the template is archived names the template
as the level to activate.
tektona template rm takes the whole template: its versions, their tags and
its build records, a running build included. It cannot be undone. Archive the
template instead to refuse new sandboxes reversibly.
The build records outlive the template. A build you know the id of still reads
after its template is gone: tektona template build get <id> answers with the
status, the error, the timings and the resources it ran on, and marks the
template deleted. Its log reads too, for as long as the log itself is kept —
seven days from when each line was written.
They are the part nothing else holds, so the delete still asks first when the template has any, and says how many:
$ tektona template rm go-dev
This deletes go-dev and its 12 build records. They cannot be recovered.
Type y to continue:--yes skips the question, and is required when stdin is not a terminal, so a
scripted delete says what it means instead of stopping on a prompt nobody can
answer. A template with no build records is deleted by one command either way.
tektona template get reports the same number as stats.builds.total, so you
can see it before you delete. It is not succeeded plus failed: a pending or
a running build is in neither, and the delete takes those too.
The delete reports what it destroyed:
$ tektona template rm go-dev --yes
Deleted go-dev. 12 build records went with it, and cannot be recovered.A build whose template is gone is reachable by its id and appears in no list:
tektona template build ls reads within a template, and there is no longer one
to read within. Keep the id if you want the record. Tektona removes a record
whose template has been gone for 90 days.
Archiving frees no storage. tektona template get reports what an archived
template still holds. The lifecycle rules restart each version's window from the
archive and reclaim from there, and they never take the 3 newest versions.
A sandbox that records any version of the template refuses the delete, the way one sandbox refuses a version delete. The refusal names up to 5 sandboxes and says how many more there are.
There is no override. To delete a template in use, delete the sandboxes first, then delete the template. Archive the template meanwhile: it refuses new sandboxes and leaves the existing ones alone.
A paused sandbox counts, and so does one whose teardown has not finished. A fork counts too: a fork inherits the version its parent recorded, so "delete the sandboxes first" means the whole fork tree, not just the sandbox you created.
tektona sandbox ls --template <ref> does not list the same set — it shows
only what you own and hides a sandbox whose delete has started. The refusal
names the command that lists all of them:
tektona admin sandbox ls --template <ref> --include-deleted --all-projectsThose two flags are different axes: --include-deleted widens which states are
listed, --all-projects widens which projects. A refusal on an org template
needs both. The command needs project admin, and org owner for
--all-projects. Without that role, tektona sandbox ls --template <ref> --include-deleted --scope all shows the ones you can see, which is fewer.
tektona template get and tektona template ls both report how many sandboxes
a template holds, so you see the number before you run the delete. A platform
template (tektona/...) shows a dash instead: its sandboxes span every
organization, and no one deletes a platform template.
Choosing a base image
References resolve the way docker pull resolves them. A name with no tag and
no digest means :latest, so fedora and fedora:latest are the same image.
A @sha256: digest pins exact bytes.
Every build records the digest it resolved onto the version it mints, so the version is reproducible whichever form you write. A moving tag decides which bytes the next build picks up, not which bytes an existing version holds.
Common bases work, ubuntu:24.04 and python:3.13-bookworm among them. Your
image does not have to ship an init: Tektona's init is the first process in the
sandbox and runs your image's ENTRYPOINT or CMD.
An image with no shell builds too. The sandbox runs, serves its ports and takes
a tektona sandbox cp; only tektona ssh has nothing to open a session with,
and the build says so.
Start from a platform base. tektona template ls shows every template you can
use, and tektona template version ls shows the image and the unpacked size of each
version, so the tektona/* entries tell you what the platform currently offers:
tektona template ls
tektona template version ls tektona/sandbox-baseThe SIZE column is the unpacked image. A sandbox disk smaller than that is
refused, so it is the number a --disk has to clear.
tektona template ls gives each template a VERSIONS, TAGS and STORAGE
column. VERSIONS counts the archived versions as well as the active ones,
because an archived version still holds storage. STORAGE counts an image two
of the template's versions share once, and it says what the template holds
rather than what deleting it frees: two templates that pull the same base image
share one copy and both report it. It is blank for a template whose images all
predate the size the platform records now.
ghcr.io/tektona-ai/sandbox-base works, and is what tektona template init
writes.
If you only want a sandbox and not a template of your own, create one from a platform template directly, with no build at all:
tektona sandbox create tektona/sandbox-baseWhat a build does
A build resolves the image reference, pulls it, and converts it. When the build
names commands, it then starts a sandbox on that image, runs the commands in
order, and saves the result as the version's image. spec.sandbox travels with
the build and is recorded on the version it mints.
A build with no commands stops after the convert.
Cancelling a build
A build you no longer want is cancelled by its id:
tektona template build cancel 01BUILDThe command returns at once. Tektona then deletes the build sandbox, releases
the builder and frees the base image, which takes seconds. The build reads
cancelling while that happens, and cancelled when it is done.
A cancelled build is not a failed build. It publishes no version, it moves no
tag, and tektona template build logs 01BUILD -f exits zero — so a build you
cancel does not fail the job you cancelled it from. Ctrl-C ends the following
only; the build goes on.
tektona template build get <build-id> says who cancelled a build, which is the
question to ask when you find one cancelled that you did not cancel.
Cancelling a build needs the same access as starting one.
A build ends on its own after 90 minutes.