Skip to main content
A question (inputs) is one step of the wizard, and a placeholder ({{...}}) is a value the platform fills in when it creates the template. Questions collect what only the user knows; placeholders connect the services and generate what nobody should type.

Questions

inputs is an ordered list. Each item becomes a step of the wizard, shown in that order. How each type is checked: A secret question is typed without echo. When generate is set and the user leaves it empty, the platform generates it on the server and shows it once in the outputs. A regex is limited to 200 characters and cannot use back-references, nested quantifiers or a repeated alternation, because it runs on the server; it only applies to text types. Token question, from the starter bot:

Conditions with when

when is an equality check against one earlier question, with no expression language. equals must fit the type of that question: a boolean for boolean, a number for number, one of the option values for select. A condition on a later question, on itself or on an unknown id is refused (invalid_when, unknown_input). A question whose condition is false is skipped, and its answer does not exist.
A database or Blob service accepts the same when to be created conditionally. An app service does not; use sets.services.

Options and sets

The effect of a choice lives in the option itself. sets can do three things. When several questions touch the same service or variable, the last one wins; memory from ram_extra adds up: A template cannot end up without an app: if the chosen options turn every app off, the deploy is refused. Quote "on" and "off" in YAML so they stay text. This is how n8n offers Postgres, SQLite or workers without any expression:

Placeholders

A placeholder is written {{ ... }}. The platform resolves it when it creates the template and again when a managed value changes (for example after a database password reset). It is never resolved in the browser. Placeholders work in env (and in sets.env) and in outputs. They do not work in main, build, start or healthcheck.path; there they give unknown_placeholder. Text outside {{ }} is never interpreted, and the value of a placeholder is never expanded again, so an answer that contains {{secrets.x}} stays as plain text.

Apps and the stack

The URL and the host name follow the app: a variable whose value is exactly one of these placeholders is updated when the subdomain changes or when the user adds a custom domain. Inside a longer text (https://{{app.domain}}/x) the value is fixed at deploy time.

Databases

The app reaches the database through its public address, with client certificates. See Stacks. The ssl.*_path values are absolute paths inside the app, in /app/.vertra/certs/<database_id>/ (ca.pem, client.crt, client.key, client.pem, client.p12). The platform writes them at every start, and your process (uid 1000) can read them. prisma_url carries the password, so it is sensitive and exists only when your manifest asks for it. Postgres from n8n, with certificates:

Blob folders

Secrets and answers

Switched-off services

A placeholder that points to a service turned off by an answer resolves to an empty value, and a variable that ends up empty is not written. That is why the n8n template can list every DB_POSTGRESDB_* variable and still run on SQLite.

Managed variables

A variable whose value is a placeholder of a database, Blob folder or app is managed by the stack: it is updated on its own when the database changes password or certificate, or when the app’s address changes, and the dashboard shows a “managed by the stack” badge. Editing it by hand turns it into a regular variable.

What is refused

See Validate and test for how to fix each one.
Last modified on October 30, 2026