Templates

Shardflux templates: versioned images that workspaces start from, with environment, inputs, start commands and services, and python-node-browser.

What a template is

A template is the image a workspace starts from: an operating system, languages, packages and files, plus the settings every workspace of it gets when it opens. You name it by its slug when you open a key:

TypeScript
await cloud.workspaces.open({ key: 'customer-42/main', template: 'python-node-browser' });

Templates come in two kinds:

Kind Who publishes it Examples
Platform template Shardflux. Every project can open it. python-node-browser (category stack), ubuntu-24.04 (category os)
Organization template You, by building one or saving a workspace as one acme-dev

Versions

A template has numbered, immutable versions. When a key is opened for the first time, the slug resolves to the template's latest published version, and the workspace keeps that version for its whole life. Publishing a new version changes what new keys get; existing workspaces keep theirs. Fork keeps the source's version, and reset returns to it.

workspace.template (TypeScript) and shard ws get <key> show the slug and version a workspace runs.

Public templates

List what your project can open, and look one up:

Shell
shard templates list
shard templates get python-node-browser
TypeScript
const page = await cloud.templates.list();
for (const t of page.data) console.log(t.slug);
const detail = await cloud.templates.get('python-node-browser');
Python
print([t["slug"] for t in sf.templates.list(owner="platform").data])
detail = sf.templates.get("python-node-browser")

python-node-browser is the template these docs use. It is Ubuntu 24.04 with Python 3.12 (pip, venv), Node.js 24 (npm), git, curl, build-essential and a headless Chromium browser. A workspace of it gets 2,048 MiB of memory unless you set caps.memory_mib. ubuntu-24.04 is a minimal base (bash, apt, sudo, curl and certificates) to build your own templates on.

Look inside a version without opening a workspace:

Shell
shard templates get acme-dev                        # versions, and which one open resolves to
shard templates files acme-dev 3 /home/user          # one directory of version 3
shard templates diff acme-dev --from 2 --to 3        # what changed between two versions

Versions published before file lists existed answer 409 (details.reason: file_list_unavailable).

Settings: environment, inputs, start commands and services

A template version built from a recipe (see Build a template) or saved from a workspace carries settings that apply every time one of its workspaces opens:

Setting What it does Limits
env Environment variables for every command, terminal, start command and service 128 names; values up to 4,096 bytes; names starting with SHARDFLUX_ are reserved
inputs Values supplied when a workspace is opened: text (put into the environment) or secret (binds the stored secret of the same name) 32 inputs; text values up to 4,096 bytes, no CR, LF or NUL
start Commands run at create (first boot of a new workspace), boot (a later cold boot) or resume 32 commands; timeout_seconds 1 to 1800 (default 300), 3,600 seconds in total
services Long-running processes kept up by the workspace, with restart (always, on_failure, never) and a readiness check (port or command) 16 services; ready_timeout_seconds 1 to 600 (default 60)
defaults Default lifetime, idle_timeout_seconds for sessions, an egress ceiling (internet, allowlist, none) and resource limits

Environment precedence, lowest first: the workspace's base environment, the template's env, the workspace's text inputs, then the command's own env.

Pass inputs when you open a key:

TypeScript
const ws = await cloud.workspaces.open({ key: 'customer-42/main', template: 'acme-dev', inputs: { PROJECT_NAME: 'acme' } });
console.log(await ws.inputs(), ws.startup);
Python
ws = sf.open(key="customer-42/main", template="acme-dev", inputs={"PROJECT_NAME": "acme"})
print(ws.inputs(), ws.startup)
Shell
shard ws open customer-42/main --template acme-dev --input PROJECT_NAME=acme

On a new key, each input takes the given value, else its declared default. On an existing key, inputs replaces them all; leaving it out keeps them. A missing required input is 422 (details.reason: input_required), an undeclared one input_unknown, and a value that breaks the rules input_invalid.

Start commands and services at open

open waits for the start commands and services: a workspace is ready when they have run and its services report ready. workspace.startup shows the progress (pending, running, ready or failed).

  • Which commands run. A new workspace (and a reset one) runs its create and boot commands, in the declared order. A later cold boot runs boot commands. A resume or fork restores memory, so it runs resume commands, and the services are still running.
  • When a step fails. The open fails with startup_failed (retryable). The workspace keeps running so you can look at it: workspace.startup names the failed step, its exit code and the last 4 KiB of its output. The next open runs the failed step again.
  • Changed inputs apply to later commands, not to services that are already running.

Layered and legacy workspaces

Template versions that support it give workspaces a layered disk: the template is a read-only layer, and the workspace's own changes are a separate layer. That separation makes reset, saving a workspace as a template and listing a workspace's changes against its template possible:

TypeScript
const page = await workspace.changes({ pathPrefix: '/home/user', summary: true });   // added | modified | metadata | deleted | replaced

Workspaces created from older versions are legacy (one disk) and answer those calls with 409 (details.reason: legacy_disk_layout). The layout is chosen at the first open and never changes; workspace.diskLayout (TypeScript) and ws.disk_layout (Python) report it.

Ways to make your own template

Way When How
Build from template.yaml Reproducible templates kept in your repository Build a template
Save a workspace as a template You set a workspace up by hand or with an agent workspace.saveAsTemplate({ templateSlug }), ws.save_as_template(slug), shard ws save-as-template <key> --template <slug>
Draft (dev mode) Iterate on a template in a live workspace, test copies, then publish cloud.templates.draft(slug), sf.templates.draft(slug), shard templates draft ...

Saving and drafts need a layered workspace. Organization templates are stored once per distinct layer, and their storage counts toward your plan's retained storage (see Pricing and limits).

View this page as Markdown