Templates & expressions
Templates wire your blocks together. A {{ }} expression inside any config field is resolved before the block runs, against the data produced by earlier steps. The same grammar powers both the in-browser simulator and the compiled Go binary, so what you test is what you ship.
Syntax
Write {{ path }} anywhere in a string. Two forms behave differently:
- Interpolation — the expression is part of a larger string. It is replaced by its value as text;
null/undefinedbecome empty."Hello, {{ steps.name.value }}!" -> "Hello, Ada!" "{{ steps.fetch.body.login }} is active" - Whole value — the entire field is a single
{{ }}. The raw, typed value is returned (object, array, number, boolean), not a string. Use this for fields that expect structured data."{{ steps.fetch.body }}" -> { login: "ada", followers: 1234 } "{{ steps.choice.value }}" -> true (boolean, not "true")
Templates recurse into objects and arrays, so a reference inside headers or query is resolved too.
The context
Paths resolve against the execution context, which has two roots:
| steps | Each step’s output, keyed by id. Fields depend on the block — see the Block reference. |
| env | Environment variables of the running process. Use this for secrets. |
"{{ steps.username.value }}" # a previous text_input
"{{ steps.fetch.body.email }}" # a nested JSON field
"{{ env.API_KEY }}" # an environment variablePaths and indexing
Navigate with dots. Index into arrays with [i].
"{{ steps.fetch.body }}" # whole object
"{{ steps.fetch.body.login }}" # nested key
"{{ steps.items.body[0] }}" # first element of an array
"{{ steps.tags.values[2] }}" # third multi_select choiceA missing key resolves to undefined (empty in interpolation; the field is left blank, not an error).
Condition expressions
The condition block evaluates an expression after resolving its templates. The grammar is deliberately tiny:
| Operator | Meaning |
|---|---|
| == != | Strict equality (same type AND value). No coercion. |
| > < >= <= | Numeric comparison. Non-numbers → false. |
| and | All parts must be true. |
| or | Any part must be true. |
Literals are recognized automatically: true/false, numbers, and quoted-less bare strings.
"{{ steps.fetch.status }} == 200"
"{{ steps.confirm.value }} != false"
"{{ steps.fetch.body.followers }} > 1000"
"{{ steps.env.value }} == prod and {{ steps.dryrun.value }} == false"A comparison with no operator is tested for truthiness. The falsy values are "", false, 0, null, and undefined; everything else is truthy.
Limitations (be aware)
The expression engine is intentionally minimal. It does not support:
- Nested or mixed
and/orwith precedence — keep conditions to a singleandor a singleor. - A
notoperator — invert with== falseor!=. - Arithmetic, string concatenation, or parentheses.
- Regular-expression matching. Use a
set_variableplus a comparison instead.
For anything richer, the downloaded project is plain Go — edit internal/blocks.go and rebuild.
Worked examples
Chain a template through set_variable — compute a greeting, then print it:
[
{ "id": "name", "type": "text_input", "config": { "label": "Name" } },
{ "id": "g", "type": "set_variable",
"config": { "value": "Hello, {{ steps.name.value }}!" } },
{ "id": "out", "type": "output_text",
"config": { "text": "{{ steps.g.value }}", "style": "success" } }
]Branch on an HTTP status — fetch, then show a table or an error:
[
{ "id": "u", "type": "text_input", "config": { "label": "GitHub user" } },
{ "id": "fetch", "type": "http_request", "config": {
"method": "GET", "url": "https://api.github.com/users/{{ steps.u.value }}" } },
{ "id": "ok", "type": "condition",
"config": { "expression": "{{ steps.fetch.status }} == 200" },
"branches": { "true": "show", "false": "err" } },
{ "id": "show", "type": "output_table", "config": {
"title": "User", "columns": ["login","followers"], "data": "{{ steps.fetch.body }}" } },
{ "id": "err", "type": "output_text",
"config": { "text": "Not found", "style": "error" } }
]POST with a JSON body — send the output of an earlier step:
{ "id": "post", "type": "http_request", "config": {
"method": "POST",
"url": "https://example.com/api",
"headers": { "Content-Type": "application/json", "Authorization": "Bearer {{ env.TOKEN }}" },
"body": "{{ steps.form.value }}" } }