Skip to main content

Context & expressions

The workflow context

Every execution carries a context — a nested key/value store that node configs read from and write to. It starts with the trigger payload and grows as nodes run.

PathWhat's there
trigger.*The payload passed to Workflow::run() / dispatch() (or a webhook's request body, or a model event's attributes).
nodes.<id>.*The output of the node with that id, once it has run. Non-array outputs are wrapped as { "result": <value> }.
resume.*The payload passed to Workflow::resume($id, [...]), available to the node that was waiting.
(anything else)Whatever Variable nodes write, e.g. order.status.

Expressions: {{ ... }}

Any string value in a node's config can contain {{ expression }} markers. They're resolved just before that node runs, against the current context.

['message' => 'Order {{ trigger.order_id }} total is {{ nodes.calc-total.result }}']

Resolution rules:

  • A string that is exactly one {{ expression }} returns the raw resolved value with its type preserved (a number stays a number, an array stays an array).
  • A string with {{ }} embedded in other text interpolates — the resolved value is stringified (arrays become JSON) and spliced in.
  • Resolution is recursive through nested arrays in a node's config.
  • An expression that doesn't resolve yields null (embedded, it renders as an empty string) rather than throwing.

Path + method chains

An expression is a dot path optionally followed by a chain of method calls:

nodes.list-users.result.first().name.upper()
└──────── path ────────┘└ methods ──────────┘

The path is looked up in context with dot notation. Each method is then applied to the running value. Method arguments are comma-separated literals — quoted strings, numbers, true / false / null.

Expressions do not have arithmetic or comparison operators. Use the Condition / Switch nodes for branching, and the Math / Text nodes (or the method helpers below) for transformations.

{{ item.* }} — deferred

Inside the per-item field of a collection node ({{ item.status }}, {{ item.email }}), item is not resolved by the engine's normal pass — the node binds each element to item itself as it iterates. item is the only deferred keyword.

Chainable method reference

All methods are applied left to right. A method that doesn't apply to the value's type generally passes the value through unchanged; an unknown method name raises an error.

Array / collection

MethodResult
first() / last()First / last element, or null.
count() / length()Element count (string length for strings).
keys() / values()Array keys / values.
reverse()Reversed array (or reversed string).
unique()De-duplicated, re-indexed.
flatten()Fully flattened.
sum() / min() / max() / avg()Aggregate over a numeric array.
nth(i)Element at index i.
skip(n) / take(n)Drop / keep the first n.
pluck('key')Column key from an array of rows.
filter('field', 'op', value)Keep rows where field op value holds. op== != > >= < <= in.
join(', ')Implode with a separator.
sort()Ascending sort (spaceship comparison).

String

MethodResult
upper() / lower()Case.
trim(chars?) / ltrim() / rtrim()Trim.
camelCase() / snake_case() / kebab() / studly() / title() / slug(sep?)Case conversions.
limit(n, end?)Truncate to n chars with a suffix (...).
start(prefix) / finish(suffix)Ensure it begins / ends with the given string.
before(x) / after(x)Substring before / after x.
contains(x) / startsWith(x) / endsWith(x)Boolean tests.
replace(search, replace)Literal replace.
split(sep)Explode to an array.
words()Word count.
pad(len, char?) / repeat(n) / substr(start, len?) / indexOf(x)As named.
wrap(before, after?)Surround the value.

Number

MethodResult
add(n) / sub(n) / mul(n) / div(n) / mod(n)Arithmetic (division / modulo by zero yields null).
abs() / ceil() / floor() / round(precision?)Rounding.
clamp(min, max)Constrain to a range.
format(decimals?, decPoint?, thousandsSep?)number_format.

Type & logic

MethodResult
string() / int() / float() / bool()Cast.
json()Encode to a JSON string.
decode()Decode a JSON string to a value.
fallback(default)The value, or default if it's null.
isset() / empty() / not()Boolean tests on the value.
if(then, else)then when truthy, else else.

Date

MethodResult
date(format?)Parse the value and format it (default Y-m-d).
time(format?)Same, default H:i:s.
now(format?)The current time formatted (ignores the value).

Reading context directly

Custom node handle() methods receive the resolved $config array, so most never touch the context object. When you do need it:

$context->get('nodes.list-users.result', default: []);
$context->get('trigger.email', strict: true); // throws if the path is missing
$context->set('order.status', 'shipped');
$context->all(); // the full array