Solari

Templates

A template is the starting point for a machine, everything it comes with already set up. Pick a ready-made one when you create a machine, or build your own so every sandbox or VM starts with exactly the tools you need.

Ready-made templates

Pass a template name to create. Sandboxes default to base; VMs default to the standard Ubuntu desktop.

const sbx = await sandboxes.create({ template: "base" })       // headless
const desk = await desktops.create({ template: "workstation" })     // GUI
  • base: the standard headless sandbox (the sandbox default).
  • default / workstation: the standard Ubuntu desktop — XFCE with Chrome, LibreOffice and VS Code. These two name the same image today.
  • office: an Ubuntu desktop pre-loaded with LibreOffice and common office tools.
  • code: an Ubuntu desktop pre-loaded with VS Code and common dev tools.

Need something these don't cover? Build exactly the desktop you want as a custom template below — it gets a tpl_… id and works anywhere a built-in name does.

Custom templates: bring your own setup

Build your own reusable template: start from a base and add the steps you want, then create machines from it. You get back a tpl_… id that belongs to your team. Every machine you start from it comes with your tools already installed, with no setup to wait for each time.

Custom templates require a paid plan
Building one consumes a real microVM, so it's gated the same way desktop creation is. On the free plan, POST /templates returns 402 with { code: "FeatureRequiresPlan", error: "Custom templates require a paid plan" } before anything is built.
import { SandboxClient, TemplateClient, Image } from "@solarisdk/sandbox"

const opts = {
  apiKey: process.env.SOLARI_API_KEY!,
  baseUrl: "https://api.getsolari.com",
}
const templates = new TemplateClient(opts)
const sandboxes = new SandboxClient(opts)

// Describe what you want, one step at a time.
const image = Image.base("ubuntu:22.04")
  .kind("sandbox")                       // "sandbox" (headless) or "desktop" (with a screen)
  .aptInstall(["ffmpeg", "poppler-utils"])
  .pipInstall(["pandas", "pdfplumber"])
  .runCommands("mkdir -p /work")
  .env({ HF_HOME: "/work/.hf" })
  .workdir("/work")

// Build it and wait until it's ready to use.
const tpl = await templates.build(image, { name: "media-tools" })

// Create a machine from it, with everything already installed.
const sbx = await sandboxes.create({ template: tpl.templateId })

Builder steps

Steps run in the order apt → pip → run → env → workdir:

  • aptInstall([...]): installed first, in one apt-get install.
  • pipInstall([...]): pip3 install --no-cache-dir.
  • runCommands("…", "…"): one shell command per argument, in order.
  • env({ KEY: "val" }): environment variables that stay set every time you start the machine.
  • workdir("/work"): creates the folder and uses it as the working directory for later steps.

You can also start from an existing template instead of a plain OS with Image.fromTemplate("workstation"). Uploading files from your own computer (addLocalFile() / addLocalDir()) isn't supported yet; a recipe that uses it is turned away when you build.

Build from a public image

A sandbox template can start from an OCI image instead of a Solari base. Send fromImage in the recipe of POST /templates; the tag is resolved to a digest when the build runs, and the template shows the pinned reference in its fromImage field.

curl -s -X POST "https://api.getsolari.com/templates" \
  -H "Authorization: Bearer $SOLARI_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "name": "py312",
    "kind": "sandbox",
    "diskGb": 12,
    "compiled": {
      "fromImage": "docker.io/library/python:3.12",
      "steps": [
        { "op": "run", "command": "pip install --no-cache-dir requests" },
        { "op": "env", "key": "APP_MODE", "value": "prod" },
        { "op": "env", "key": "PATH", "value": "/opt/tools/bin:$PATH" }
      ]
    }
  }'
  • Registries: docker.io, ghcr.io, public.ecr.aws, gcr.io and quay.io, with anonymous pulls only (public images).
  • Sandbox templates only. fromImage cannot be combined with base, fromTemplate or packages; install packages with a run step instead.
  • diskGb is the builder disk for an image build (default 12, at least 6).
  • At most two image builds run at once (429 TooManyBuilds). A bad reference is 400 InvalidImage, an unsupported registry 400 ImageRegistryNotAllowed.
  • In a sandbox created from the template, command and file paths are relative to the image's root.

Environment variables and PATH

An env step is saved with the template and every command you run in a sandbox created from it sees those variables. Values may refer to other variables with $NAME or ${NAME}: a reference resolves against the sandbox's own environment and the env lines above it, and a name that is not defined becomes an empty string, as in Docker. So PATH=/opt/tools/bin:$PATH puts /opt/tools/bin in front of the existing PATH.

Variables you pass when you create the sandbox or run a command still win over the template's. Sandboxes created from an older version of the base image do not pick these variables up; create a new one.

Manage templates

await templates.list()               // ready-made templates + your team's custom ones
await templates.get(tpl.templateId)  // check its status: building | ready | failed
await templates.delete(tpl.templateId)
Match the type when you create
A sandbox template only works with sandboxes.create, and a desktop template only with desktops.create. Mixing them is turned away.

Deleting

  • A template that is still building can't be deleted yet, and ready-made templates can't be deleted either.
  • A ready template can be deleted even while machines created from it are still running. Those machines keep working on their own and aren't affected.
  • Your custom templates stick around and stay ready to use until you delete them.
Templates vs. snapshots
A snapshot makes ready-to-go copies of one machine you prepared. A template is a reusable, named starting point you create brand-new machines from. Build it once and share it across your team's sandboxes and VMs.