Skip to main content
A template is a curated Docker Compose file for a well-known service (n8n, Uptime Kuma, a Postgres-backed app, a local LLM runtime). Deploying one fills in a Compose body for you and sends it through the same endpoint as levelrail-cli apps deploy-compose. There is no separate template deploy path, so a template-deployed app behaves like any other Compose app. Some templates also come with an install manifest: a short list of settings (generated secrets, values with defaults, required values) and the services you can put behind a domain. Their template page shows an Install form, and levelrail-cli templates install <id> does the same from the CLI. See Compose apps. This page covers how to deploy templates, how $SERVICE_... variables work, and how to save your own apps as templates. To see what is in the catalog, read the template catalog. The seven multi-service wiring examples are described in Starter kit templates.

Deploy a template

Open Apps, choose New app, then Browse templates. Search by name, slogan or category, or pick a category. Selecting a card pre-fills the app name (the template ID) and an editable Compose body. Review it, replace any $SERVICE_... token you want to set yourself, and deploy. The result lists each deployed service with a link to its app page.
A Compose document becomes one app with one service per Compose service, each reconciled independently.

How templates are defined

The built-in catalog is compiled into the control plane binary and served from memory: there is no catalog table and no admin screen. Adding or changing a built-in template means shipping a new control plane build. Each entry has an ID, name, slogan, category, documentation link, a Compose body, and two optional hints:
  • Recommended memory: a static hint shown as a badge (for example “~6 GiB RAM recommended”). It is a rule of thumb and is not checked against any node’s free memory.
  • Requires GPU: the entry reserves an NVIDIA GPU through deploy.resources.reservations.devices. It needs a node with a GPU and the NVIDIA container runtime; see AI models.
Only the resources.reservations.devices and replicas keys of a Compose deploy: block are read. Other Swarm-only keys are reported rather than silently ignored.

Magic variables

Templates use $SERVICE_<KIND>_<NAME> tokens in place of literal secrets. At deploy time:
  • PASSWORD, USER, BASE64, HEX and REALBASE64 tokens are generated and stored as secrets. Every reference to the same name gets the same value, so an app and its database agree on $SERVICE_PASSWORD_DB. A generated value is never written into the stored Compose body.
  • FQDN tokens resolve to https:// plus the service’s assigned domain, when the Compose file assigns one.
  • Any token written with a default (${SERVICE_FOO:-value}) uses that default.
  • Anything else has no value and is reported as unresolved. A template with an unresolved token is marked requires_configuration, and the one-click route refuses it. Deploy it through the dashboard’s Compose editor, or with apps deploy-compose, after filling the value in.

Save an app as a template

Custom templates turn an app you already run into a reusable one-click template. They are stored in the database, not in the binary.
1

Save the app

On the app’s detail page, open the overflow menu and choose Save as template, or run:
Levelrail derives a Compose body from the app’s current desired state (one service, or every service of a multi-service app) and saves it with an ID of the form custom- plus 16 hex characters.
2

Find it

In the dashboard it appears under Your templates in the same template grid. From the CLI, levelrail-cli templates list --custom.
3

Deploy or delete it

A custom ID works anywhere a catalog ID does:
Deleting removes only the saved template. The source app and apps already deployed from it are untouched.
A custom template never contains a secret value. Secret, database-derived, and Vault env entries carry only a key name or reference, and each one becomes a ${SERVICE_SECRET_<key>} placeholder. SECRET is not a generated kind, so such a template always has requires_configuration set and must be deployed through the Compose editor, where you supply the real values. The saved Compose body does not capture everything about the app:
  • Domains stay with the source app. A new app starts with none, as with apps clone.
  • Host port, bind address and bind mounts are specific to the source machine.
  • Resources and health checks have no Compose representation Levelrail can read back, so they are dropped.

Static sites

An app whose app.yaml sets build.type: static has no container. The control plane copies the built output to a directory on its own host and Caddy serves it directly. These sites are created only by a git push to such an app. levelrail-cli static-sites list (and GET /api/v1/static-sites) lists their names and domains, and the Apps page shows a read-only Static sites card when any exist. See app.yaml reference for the build types.

API and CLI reference

templates delete only removes custom templates; the built-in catalog is read-only.

Limits

  • There is no versioning. A template’s Compose body can change between control plane releases, and nothing records what an already-deployed app was created from.
  • Importing a catalog from an external source is not supported: the built-in set is the one in the template catalog. The reasoning is in ADR 015.

Next steps

Template catalog

Every built-in template by category.

Starter kit templates

Seven multi-service wiring patterns.

Deploying apps

Roll out, roll back and operate what you deployed.

app.yaml reference

Build types and service settings.
Last modified on October 12, 2026