How flows work
How nodes connect, what edges carry, and how wire data differs from {{input}} / {{nodes}}
A flow is a directed graph of nodes. Edges decide run order. The JSON that travels across an edge is the wire (execute input of the next node). Templates like {{input.*}} and {{nodes.id.*}} are a separate layer.
Quick picture — how data moves
Labels on the arrows show what JSON the next node receives as execute input.
demo-main-nodes.flow.json. Later strings can also use {{nodes.fetchProduct.body.title}}.How nodes connect
Sketches with a red Fails validation badge show an invalid graph. Those cases break quester validate and desktop save checks.
Required. No incoming edges. At most one outgoing edge. This sketch is valid — zero starts, two starts, or http → start fail validation.
Orphan steps have no path from start. They fail validation (except note stickies).
The graph must be a DAG. a → b → a (or any longer loop) fails validation.
No handles. Any edge to or from a note is invalid. Notes may sit disconnected.
Fails validationEach edge’s source and target must equal an existing node id in that flow. Typos, renamed nodes, and deleted ids all fail (same for a bad source).
Every node id in a flow must be unique.
Fails validationPorts (handles) and edges
Desktop shows target (in) and source (out) ports. Branch nodes expose named source handles.
In ×1 · out ×1. Fan-out allowed — several children get the same wire.
In ×0 · out ×1 · max one outgoing edge.
In ×1 · out ×0. Terminal for that path.
In ×1 · one named handle per case + default. Only the matching case runs.
In ×0 · out ×0 · no edges.
Branch: only the matching handle runs (here
true → A); the other edge is skipped.One incoming edge per node, except join which accepts N. For diamonds or reconvergence after branches, insert a join (collect-map of predecessor outputs). Deep-merge named bags with merge (still one wire in).
Wire data vs templates
When http finishes, the next node’s execute input is already the response object.
On extract, assert, json, if checks: body.title, status, products[0].id.
Any later string field, by node id.
Run panel / CLI --input — not the same as the input node.
{{env.API_BASE}}, {{secrets.TOKEN}}, {{vars.token}}.
There is no {{previous.*}} mustache scope. Previous output is already the wire.
Three meanings of “input”
JSON on the wire into execute() (previous node output).
Object from Run panel / CLI --input.
input node
Copies run input onto the wire for the next step. Optional if you only need {{input.field}}.
How a step runs
- Resolve templates in that node’s string fields.
- Call
execute(wireJson, context). - Store the return value as
{{nodes.<id>}}. - Enqueue next edges (all for linear fan-out; filtered by handle for branches).
Cheat sheet
| I need… | Use |
|---|---|
| Field from the last HTTP response in extract | body.id / products[0] |
| Same field later in a string | {{nodes.httpId.body.id}} |
| Run panel field | {{input.field}} |
| Env / secret / set var | {{env.*}} / {{secrets.*}} / {{vars.*}} |
| Sticky text on canvas | note (not executed) |
Related
- Template syntax
- Nodes overview — ports per type
- Getting started