Passing Data Between Steps
How data flows from the trigger through each step of your workflow.
Passing Data Between Steps
This page is about the mental model — how data moves through a running workflow. For the exact template syntax, see field mapping.
The mental model
The rule to hold in your head is simple: each step produces exactly one output object when it succeeds, and that output is kept around for the rest of the run.
As the executor walks the graph, every successful step writes a step_completed event into the run journal with its output payload attached. Those events aren't ephemeral — they're persisted per-run, and any step that runs later can read them back by node ID. You never have to chain data hand-to-hand from one node to the next: once something is produced, it stays addressable.
This is the single insight that explains everything else on this page. Workflows don't pass data along an edge like a conveyor belt. Edges control order of execution; data lives in the run's history, available to any step that comes after.
Walking through a run
Picture a three-step workflow:
- An Inbound Webhook trigger receives:
{ "email": "alice@acme.io", "name": "Alice" } - An HTTP step calls a company-lookup API using the email and returns:
{ "company": "Acme Inc.", "industry": "B2B SaaS" } - A Google Sheets step appends a row with both the contact details and the enrichment result.
Here's what each step "sees" when it runs:
- HTTP step. The trigger has already completed. The webhook's output (
email,name) is in the journal under the trigger's node ID. The HTTP step reads from it to build its request. - Sheets step. Both the trigger's output and the HTTP step's output are in the journal. The Sheets step can pull
emailandnamefrom the trigger andcompanyandindustryfrom the HTTP step in a single row — it doesn't have to go through the HTTP step to reach the trigger's data.
The arrow from Webhook → HTTP → Sheets doesn't mean "Sheets only sees HTTP's output." It means "Sheets runs after HTTP finishes." Every ancestor's output is still on the table.
Addressing outputs
At a glance, you reference another step's output by writing a template expression in any inspector field:
- The trigger uses a reserved root name:
trigger. Internally the trigger is stored under a node ID liketrigger_1, but you don't have to care — the resolver finds it either way. - Every other step is addressed by its node ID, which the canvas assigns when you drop the node in. Open a node's inspector to see its ID.
The field-mapping picker in the inspector writes these for you, so you rarely type them by hand. For the full syntax — delimiters, dot paths, whole-value vs inline, coercion, pitfalls — see field mapping.
Multiple upstream parents
Sometimes a node sits downstream of two branches that split earlier and now reconverge. A common case: a Condition node splits into a "yes" and a "no" branch, each doing its own work, and a final notification node takes edges from both.
The mental model still holds. Whichever branch actually ran contributes its outputs to the journal; the notification node can reference any ancestor's output by node ID. It doesn't matter how many hops away the ancestor is or which branch it lived on — if the node ran and succeeded, its output is addressable.
One caveat: if a branch was skipped (for example, because a Condition routed the run the other way), the nodes in the skipped branch never produce output. References to them resolve to undefined.
Heads-up: the system-nodes overhaul now in design will introduce explicit Merge semantics that formalize how reconverging branches combine their outputs. Until then, reach for ancestors by node ID and guard against the skipped-branch case in your field mappings.
Loop context
Inside a Loop body, each iteration processes one item from a list. The Loop node exposes the current item so the steps inside the loop body can read it per-iteration.
The exact addressing for "the current loop item" and for outputs produced inside the loop body is under active redesign alongside the broader system-nodes overhaul. The present-day pattern: use the Loop node's item variable from inside the body, and avoid relying on fine-grained per-iteration output shapes outside the loop until the new semantics land. When in doubt, keep the work that needs per-item data inside the loop body, and aggregate with a Code node if you need to collect results.
Related
- Field mapping — exact template syntax and coercion rules
- Workflow Builder Overview — DAG model, nodes, edges
- Debugging runs — inspecting what each step actually produced