Quester Studio

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.

Data moving along start → input → http → extract start entry {} input run payload { productId } http URL uses {{input.productId}} { status, body… } extract JMESPath body.title "Mascara" Wire = previous output. extract / assert / json read it with JMESPath — not mustache.
Same shape as 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.

Exactly one start

Required. No incoming edges. At most one outgoing edge. This sketch is valid — zero starts, two starts, or http → start fail validation.

Executable nodes must be reachable from start

Orphan steps have no path from start. They fail validation (except note stickies).

Fails validation
No cycles

The graph must be a DAG. a → b → a (or any longer loop) fails validation.

Fails validation
note stays offline

No handles. Any edge to or from a note is invalid. Notes may sit disconnected.

Fails validation
Edges need real node ids

Each 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).

Fails validation
Duplicate node ids

Every node id in a flow must be unique.

Fails validation

Ports (handles) and edges

Desktop shows target (in) and source (out) ports. Branch nodes expose named source handles.

Linear step

In ×1 · out ×1. Fan-out allowed — several children get the same wire.

start

In ×0 · out ×1 · max one outgoing edge.

output

In ×1 · out ×0. Terminal for that path.

if / try

In ×1 · two named outs. Engine follows matching sourceHandle.

switch

In ×1 · one named handle per case + default. Only the matching case runs.

note

In ×0 · out ×0 · no edges.

fan-out — every child runs http 1st assert 2nd extract same wire JSON branch — one path only if true · runs A false · skipped B
Fan-out: both children run, one after another (not in parallel), in the order edges are listed in the flow file — here assert then extract. Each gets the same http response as execute input.
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.

Wire / JMESPath

On extract, assert, json, if checks: body.title, status, products[0].id.

Named node template

Any later string field, by node id.

Run input template

Run panel / CLI --input — not the same as the input node.

Env / secrets / vars

{{env.API_BASE}}, {{secrets.TOKEN}}, {{vars.token}}.

There is no {{previous.*}} mustache scope. Previous output is already the wire.

Three meanings of “input”

Execute input

JSON on the wire into execute() (previous node output).

Run input

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

  1. Resolve templates in that node’s string fields.
  2. Call execute(wireJson, context).
  3. Store the return value as {{nodes.<id>}}.
  4. 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 extractbody.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 canvasnote (not executed)