Browse documentation
Guide Updated 25 September 2026

Use fields from an earlier step

Reference an earlier step's output in a URL, header, body, or condition, and understand the names those fields are known by.

View as Markdown

Steps below another one can read what it produced. The reference is always the step's API Name, then the path to the value inside its output.

Outcome

A step uses values that came from an earlier step, rather than hard-coded ones.

Before you start

The earlier step must have been tested or sampled, or there is nothing for Hodoflow to offer you. See Configure and test a step.

1. Know what a field is called

Every step has an API Name at the top of its inspector — a short identifier made of letters, numbers, and underscores, unique within the workflow. That is how everything downstream refers to it.

If a step named Fetch rate has the API Name fx, and its response was {"base": "USD", "rates": {"EUR": 0.86}}, then the fields available below it are:

fx.base
fx.rates.EUR

Nested values are reached with dots. The trigger's own payload is available as input — and trigger is accepted as a synonym for the same thing.

One record, or a list of them

Every step hands down one of two things, and it decides how you name what is inside it. This is the rule the whole builder follows:

What the step hands down How you reference it
One record fx.base — the field, straight off the step
A list of records orders.data for the whole list; item.total for each record, inside a step that runs once per item

A step that hands down a list carries a list badge on its card, and a step running once per item carries a per item badge — so you can see where the flow widens without opening anything.

item only exists inside a step that is running once per item. Set that up in the step's Iteration section: Mode → Run once per item, then pick the list under For each item in. When you click a per-record field in the Available fields list of a step that is not doing that yet, Hodoflow asks whether it should — say yes and it is set up for you, with the reference inserted as item.<field>.

Reading orders.total off a list-shaped step resolves to nothing, so activation refuses it and names the fix. See Activation errors.

2. Insert it

In an HTTP Request or API Request step, values go in as {{field}} template variables. They work in the URL, in any Query Param or Header value, and in the Body.

An Available fields panel sits above the Test Request button, listing every upstream field as a clickable chip. Click into the input you want first, then click a chip: the template is inserted at the cursor rather than appended to the end.

https://api.example.com/orders/{{input.order_id}}

Anything you type that is not a {{field}} is sent exactly as written, so a body holding "usd" sends usd.

In a JSON body, a value that is only a {{field}} keeps the field's own type — a number stays a number rather than becoming text — anywhere in the document, including inside a list. Mix it with anything else and the result is text, which is what you want for something like order-{{input.order_id}}.

{ "amount": "{{input.order.total}}", "currency": "usd" }

sends {"amount": 4200, "currency": "usd"}.

In a Conditional step, branch conditions are formulas over the same names — input.total > 100. In a Filter List step, the condition is evaluated per item, where the current element is item.

Checkpoint: the field appears inside double braces in the input, and the chip list still shows it as available.

Fields about the run itself

Not everything a step needs comes from the step above it. flow is available in every step of every workflow and describes the run it is part of:

Field What it holds
flow.name The workflow's name
flow.id The workflow's id, which stays the same across every version you save
flow.run_id This run's id — useful as a correlation or idempotency value on an outgoing request
flow.workspace The workspace's name
flow.started_at When this run started
flow.last_run_at When the previous run of this workflow started, whatever happened to it
flow.last_successful_run_at When the last run that succeeded started
flow.last_run_status succeeded, failed, or whatever state the previous run is in

The timestamps are written as 2026-09-13T02:00:00Z.

This is what lets a step ask for only what has changed:

https://api.example.com/orders?updated_since={{flow.last_successful_run_at}}

Two things about that example are worth knowing before you rely on it.

The watermark is when the last successful run started, not when it finished. A run that starts at 02:00 and finishes at 02:05 may or may not have seen records created during those five minutes. Using the start time means the next run reads that window again — a few duplicates, which a data model's identity absorbs — instead of skipping it forever.

On the first run there is no previous run, so the value is empty. The example above sends ?updated_since= that first time, which most APIs read as no filter at all and answer with everything. That is usually what you want — a full first load, incremental after that — but if it is not, a computed value can state a floor for that first run. See below.

Every value is fixed when the run starts and stays fixed for the whole run, so a run that pauses on a Delay for a week resumes with the same values it began with, and two runs of the same workflow never read each other's timestamps.

Inside a subflow, flow describes the subflow's own run, not the workflow that called it. A subflow reads what its caller passed in under params instead — see Step types.

Values a step works out for itself

A {{reference}} inserts a value exactly as it is. It does no arithmetic, so when an API wants the watermark in some other shape, a reference alone cannot get you there. Plenty of them do: a filter that takes a unix timestamp, a date with no time, or an id that has a time encoded in it.

Every step has a Computed values section in its inspector for that. Give a value a name and a formula, and read it back anywhere that step takes a value — a URL, a query parameter, a header, a body field:

Function What it does
NOW() The current time
DATE_ADD(date, amount, unit) Shifts a date. A negative amount goes back. Units: second, minute, hour, day, week, month, year
DATE_DIFF(later, earlier, unit) Whole units between two dates — second through week
EPOCH(date) Unix time in seconds
EPOCH_MS(date) Unix time in milliseconds
FORMAT_DATE(date, pattern) Renders a date — '%Y-%m-%d' gives 2026-09-13
PARSE_DATE(value) Reads a date from text or from a unix timestamp

So an API that filters on unix seconds gets a computed value named since:

EPOCH(flow.last_successful_run_at)

and the step's parameter reads {{vars.since}}.

Give the first run a floor with COALESCE. With no previous run the watermark is empty, and every function above answers an empty date with an empty value. COALESCE takes the first value that is actually there, so this reads the watermark when there is one and thirty days back when there is not:

EPOCH(COALESCE(flow.last_successful_run_at, DATE_ADD(NOW(), -30, 'day')))

A computed value can build on another one. They are resolved in whatever order their dependencies require, so one may read another as vars.<name>. That is what makes a filter like Discord's reachable — its message list takes an id rather than a time, and an id is derived from one:

ms = EPOCH_MS(COALESCE(flow.last_successful_run_at, DATE_ADD(NOW(), -30, 'day')))
message_id = (vars.ms - 1420070400000) * 4194304

Not every API has a way to ask, whatever you can compute. Discord, to stay with it, has no "edited since" filter in any form — so a message edited after you last read it cannot be found by asking, only by reading the window again.

Renaming a computed value updates the places that read it, within that step.

3. Renaming, and what it costs

Changing a step's API Name does not update the references that point at it. Anything using the old name silently stops resolving, which usually shows up as an empty value rather than an error.

Set the API Name when you add the step. If you must change it later, search the workflow for the old name first.

Mapping into a data model

Putting values into a warehouse record is a different job with its own panel: select a Map to Data Model step and press the Map to button. That panel is click-then-click, supports reusable formulas, and is covered in Persist workflow data.

Reshaping without saving a record

A Data Transform step uses the same panel to build a shape of its own rather than a data model's: select the step and press Edit mappings. The left pane is the same searchable index of upstream fields and reusable formulas; the right pane starts empty, and + Add field adds an output field you name yourself. Click a source field on the left, then the output field on the right, to connect them.

Whatever the panel lists becomes the step's output, so the step below reads <api name>.<field> for each one. A step with no mapped field stays incomplete and refuses activation with add at least one field mapping.

Common problems

The chips list is empty. Nothing upstream has been tested. The inspector says No upstream schema yet. Test an upstream HTTP node to discover its fields.

A template resolved to nothing. The path is wrong, or the API Name changed. Check the exact path in the Available fields list — fx.rates.EUR is not fx.EUR.

API Name must be unique. Two steps in this workflow have the same API Name. Rename one.

The API Name box rejects what I typed. Only letters, numbers, and underscores are accepted. No spaces, no hyphens.

Next step

Save, version, and activate.

Related documentation