- Documentation
- Workflows
- Reference data with expressions
Reference data with expressions
Reference upstream data with the $trigger, $steps, $input, and $meta aliases and JSONata syntax, plus the scope bindings and error codes.
What an expression is
An expression is a small piece of JSONata that you type into a node field to pull a value out of the data your workflow has already produced. When you write $trigger.email into an action's "To" field, TaskJuice evaluates that expression at run time and substitutes the live value.
Expressions are the only way to map data between nodes. You reference upstream output through a fixed set of aliases, each bound to a different slice of the run. The editor highlights aliases as you type, opens an autocomplete dropdown when you type $, and lints the expression inline.
Top-level aliases
These four aliases are available in every expression field. Each binds to a different part of the run context.
| Alias | Binds to | Shape |
|---|---|---|
$trigger | The trigger node's output payload. An alias for the trigger step's output. | Whatever the trigger emits (object) |
$steps | An immutable snapshot of every prior node's output, keyed by node ID. | Object keyed by node ID, each entry { data, meta } |
$input | The current node's input payload. | Object |
$meta | Engine metadata for the run, such as routing decisions and timing. | Object |
The current node's own output data is also available as the implicit root $. An empty expression returns the node's output unchanged, so $ and an empty field behave the same way.
You may see $vars (run-scoped variables) listed in the reference picker as "coming in Stage 4."
It currently binds to an empty object, so any value you read from it will be missing. Do not
depend on $vars in a published workflow.
Reading from $steps
Every node you reference through $steps exposes two keys:
| Key | Holds |
|---|---|
.data | The node's output payload (the values later nodes consume). |
.meta | Engine metadata for that node, such as routing decisions. |
Reference a step by its node ID. When the ID is a plain word (letters, digits, underscores) you can use dot access directly. When the ID contains hyphens or spaces, wrap it in backticks.
$steps.action1.data.result
$steps.action1.data.order.total
$steps.`branch-1`.meta.routingThe node ID is the stable identifier shown in the reference picker, not the display name you see on the canvas. Pick references from the picker to get the exact ID and quoting right.
Reading a Table step's cells by column name
A Table step answers its rows twice. items (or row) holds the cells keyed by each column's id, as it always has. Beside it, itemsByName (or rowByName) holds the same cells keyed by column name, in the same order. Find and Export answer itemsByName; Create, Update, Find or Create, and Increment answer rowByName.
$steps.find.data.itemsByName[0].Session
$steps.find.data.itemsByName[0].`Thread ts`
$steps.save.data.rowByName.Email- Names with spaces or other characters are read with backticks, as above. Square brackets do not work:
itemsByName[0]["Thread ts"]is a filter in JSONata and returns the whole row. Pick the field from the reference picker to get the quoting right. - A name two columns share is left out of
itemsByNameandrowByName, for both columns. Rename one of them, or read the cell by id fromitems. - A name with a backtick (`) in it is left out, because no expression can spell it.
- Renaming a column changes its name here, so expressions that read the old name find nothing. Expressions that read
itemsby id keep working.
Passing a row to a later Table step
A Table step also answers the id of each row it returns, so a later step can change that exact row. Find and Export answer rowIds, one id per row of items, in the same order. Create, Update, Find or Create, and Increment answer rowId. Put the id in the Row id field of Update Row, Delete Row or Increment Counter.
$steps.find.data.rowIds[0]
$steps.save.data.rowIdFor a table with a primary key column, the id is that column's value. Otherwise it is an id the table made when the row was added.
Scope bindings
Some nodes introduce extra bindings that are only valid inside that node's body. These are lexically scoped: an inner scope shadows an outer one, and referencing a binding outside its node produces an error.
| Binding | Bound inside | Holds |
|---|---|---|
$currentItem | A Loop node's body when its type is "Array Iteration" | The current array element. |
$currentIndex | A Loop node's body when its type is "Array Iteration" | The zero-based index of the current element. |
Inside an array Loop you reference the item you are iterating over with $currentItem and its position with $currentIndex:
$currentItem.email
$currentIndex + 1The expression engine also defines $error (a caught error) and $event (a resumed event
payload). $error is bound on a node's error recovery branch when you set its On Error mode to
"Route to recovery branch", and carries the structured error (code, message, the failing item, and
the loop iteration index). With On Error "Continue" there is no $error; read the error from the step
itself: $steps.<step>.meta.error. $event is bound downstream of a Wait-for-Event node.
Link to a step that waits: $resumeUrl
$resumeUrl('<step id>') returns the link that resumes a later Wait for Event or Display Form step in the same run. Use it to send that link from an earlier step, for example an email that asks a client to fill in a form. The referenced step must come after the step that uses the expression and must not sit inside a Loop, because its link changes on every pass.
To find the step id, open the Wait for Event or Display Form step: its id appears under the step name next to Step ID, with a button that copies it. The reference picker lists only steps that run before the one you are editing, so it does not show this step.
$resumeUrl resolves in app actions, HTTP Request, Respond, and Voice Agent steps. See Send the form link.
"Please reply: " & $resumeUrl('client-reply')JSONata syntax you will use most
JSONata is a full expression language. The pieces that come up most when mapping workflow data:
| Pattern | Example | Result |
|---|---|---|
| Field access | $trigger.customer.email | "ada@example.com" |
| Array projection | $steps.list.data.items.id | An array of every id |
| Array index | $steps.list.data.items[0].id | The first item's id |
| Filter | $steps.list.data.items[status="open"] | Items where status is "open" |
| String join | $trigger.first & " " & $trigger.last | "Ada Lovelace" |
| Conditional | $input.total > 100 ? "high" : "low" | One of the two branches |
| Function call | $uppercase($trigger.code) | The uppercased string |
| Platform function | $formatDate($trigger.created, "MMM d, yyyy") | "Oct 4, 2026" |
Beyond JSONata's own functions, TaskJuice adds functions for dates and time zones, text, checks, lists, hashing and links. See expression functions for the full list.
Expressions can return any type: a string, number, boolean, object, or array. Whatever the expression evaluates to becomes the field's value at run time.
An expression that evaluates to null or undefined fails with NULL_RESULT rather than writing
an empty value. If a field is legitimately optional, guard it: $exists($trigger.note) ? $trigger.note : "".
How the editor helps
The expression editor is a code field with three aids:
- Autocomplete. Type
$to open a dropdown of available references, ranked by scope ($inputfirst, then$trigger,$steps,$vars,$meta). - Reference picker. Open the picker to browse references grouped by scope and insert one without typing. It lists field paths discovered from each upstream node's pinned test output.
- Inline linting. Syntax errors are flagged in place as you type.
The picker only shows the fields it can see. To populate it with real upstream fields, test the upstream node first so its output is pinned. See map data between nodes for the full workflow.
Error codes
When an expression fails, TaskJuice reports one of these codes. Use them to tell a typo apart from a missing upstream value.
| Code | Message | What to check |
|---|---|---|
INVALID_SYNTAX | Expression contains a syntax error and could not be compiled. | A typo in the JSONata: an unclosed bracket, a stray operator, a missing backtick on a hyphenated node ID. |
MISSING_NODE | Referenced step ID not found in execution context. Ensure the referenced step has completed before this step runs. | The node ID in $steps.<id> is wrong, or that node runs after this one rather than before it. |
MISSING_PATH | The referenced step exists but the specified path was not found in its output. | The node ran, but the field you asked for is not in its output. Re-test the upstream node and pick the path from the picker. |
NULL_RESULT | Expression evaluated to null or undefined. | The expression resolved to nothing. Guard optional values with $exists(...). |
EVAL_FAILURE | Expression evaluation failed at runtime. | A runtime problem such as a type mismatch (for example, calling a string function on a number). |
SCOPE_BINDING_OUT_OF_SCOPE | This identifier is not bound at the current cursor position. Move the reference inside the scope-introducing node's body, or remove it. | A scope binding such as $currentItem used outside the Loop node that introduces it. |
Example: a failed reference
Say an action references $steps.action1.data.id, but the upstream node's ID is actually create-contact. The reference compiles cleanly (it is valid JSONata) and then fails at run time with MISSING_NODE, because there is no step keyed action1. The fix is to reference the real ID, with backticks because it contains a hyphen:
$steps.`create-contact`.data.idLimits
- The reference picker reads field paths from pinned test output down to a maximum depth of 5 levels. Fields nested deeper still resolve at run time; they just will not appear as suggestions.
- Branch node conditions are not free-form expressions. The condition
fieldis a JSONata path, but you choose the operator and value from a fixed list in the condition builder. See control flow nodes.
Related
- Map data between nodes walks through wiring upstream output into a field with the picker.
- Expression functions lists every function TaskJuice adds, with an example for each.
- Control flow nodes covers Branch, Switch, Loop, and Parallel, including where
$currentItemis bound. - Triggers and actions explains how each step's output becomes context for later steps.