Skip to main content

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.

AliasBinds toShape
$triggerThe trigger node's output payload. An alias for the trigger step's output.Whatever the trigger emits (object)
$stepsAn immutable snapshot of every prior node's output, keyed by node ID.Object keyed by node ID, each entry { data, meta }
$inputThe current node's input payload.Object
$metaEngine 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.

$vars is reserved, not active yet

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:

KeyHolds
.dataThe node's output payload (the values later nodes consume).
.metaEngine 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.routing

The 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.

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.

BindingBound insideHolds
$currentItemA Loop node's body when its type is "Array Iteration"The current array element.
$currentIndexA 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 + 1
$error and $event are not reachable today

The expression engine also defines $error (a caught error) and $event (a resumed event payload), bound inside Try/Catch and Wait-for-Event nodes. Those node types are not in the Add node panel yet, so you cannot reach $error or $event from the editor. Only the Loop bindings above are usable today.

JSONata syntax you will use most

JSONata is a full expression language. The pieces that come up most when mapping workflow data:

PatternExampleResult
Field access$trigger.customer.email"ada@example.com"
Array projection$steps.list.data.items.idAn array of every id
Array index$steps.list.data.items[0].idThe 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

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.

Returning null is an error

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 ($input first, 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.

CodeMessageWhat to check
INVALID_SYNTAXExpression 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_NODEReferenced 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_PATHThe 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_RESULTExpression evaluated to null or undefined.The expression resolved to nothing. Guard optional values with $exists(...).
EVAL_FAILUREExpression 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_SCOPEThis 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.id

Limits

  • 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 field is a JSONata path, but you choose the operator and value from a fixed list in the condition builder. See control flow nodes.
Was this helpful?