Skip to main content

Expressions

Node and trigger config values can reference data produced earlier in the workflow using {{ }} expressions. Any config field whose help text says "Supports {{variables}}" accepts this syntax.

'message' => 'Welcome {{trigger.name}}, your order #{{trigger.order_id}} is confirmed.'

Referencing data

An expression is a dot-notation path into the execution context:

PathRefers to
trigger.*The payload the trigger fired with ({{trigger.email}}).
nodes.<node-id>.*The output of a previously-executed node, keyed by its id in the workflow definition ({{nodes.check-age.result}}).
loop.*Inside a Loop node's body branch: loop.item (the current element) and loop.index.

A value that is entirely one expression (e.g. {{trigger.order}}) resolves to the underlying value with its original type preserved — an array stays an array, a number stays a number. A value with surrounding text (e.g. "Order #{{trigger.order_id}}") is resolved as a string, with arrays JSON-encoded inline.

Method chains

Append .method() calls after the path to transform the value before it's used:

{{trigger.email.lower()}}
{{nodes.query.result.first().name}}
{{trigger.tags.join(", ")}}

Arguments are comma-separated and may be string literals ('...' or "..."), numbers, true, false, or null.

Array methods

MethodDescription
first() / last()First / last element.
count() / length()Number of elements (or string length, for length() on a string).
keys() / values()Array keys / re-indexed values.
reverse()Reversed array (or reversed string).
unique()Deduplicated values.
flatten()Fully flattens nested arrays.
sum() / min() / max() / avg()Aggregate over the array's values.
nth(i)Element at index i.
skip(n) / take(n)Drop / keep the first n elements.
pluck(key)Extract key from every element.
filter(field, operator, value)Keep elements where field compares to value using operator (==, !=, >, >=, <, <=, in).
join(separator)Implode into a string (default separator , ).
sort()Sorted ascending.

String methods

MethodDescription
upper() / lower()Uppercase / lowercase.
trim() / ltrim() / rtrim()Trim whitespace (or the given characters).
camelCase() / snake_case() / kebab() / studly() / title()Case conversion.
slug(separator = '-')URL-friendly slug.
limit(length = 100, end = '...')Truncate with a suffix.
start(prefix) / finish(suffix)Ensure the string starts/ends with the given value.
before(needle) / after(needle)Substring before/after the first occurrence.
contains(needle) / startsWith(needle) / endsWith(needle)Boolean substring checks.
replace(search, replace)str_replace.
split(delimiter = ',')Explode into an array.
words()Word count.
pad(length, pad = ' ')str_pad.
repeat(times = 1)Repeat the string.
substr(start, length?)Substring.
indexOf(needle)Position of the first occurrence, or false.
wrap(before, after = before)Wrap with the given prefix/suffix.

Number methods

MethodDescription
add(n) / sub(n) / mul(n) / div(n) / mod(n)Arithmetic.
abs() / ceil() / floor() / round(precision = 0)Rounding.
clamp(min, max)Constrain to a range.
format(decimals = 2, decimalPoint = '.', thousandsSep = ',')number_format.

Type methods

MethodDescription
string() / int() / float() / bool()Cast.
json()JSON-encode.
decode()JSON-decode (into an array).
fallback(default)The value, or default if it's null.
isset()true if the value isn't null.
empty()PHP's empty().
not()Boolean negation.
if(then, else = false)then if the value is truthy, else else.

Date methods

MethodDescription
date(format = 'Y-m-d')Parses the value with Carbon and formats it.
time(format = 'H:i:s')Same, defaulting to a time format.
now(format = 'Y-m-d H:i:s')The current date/time (ignores the base value).

Any unrecognized method throws — expressions fail loudly rather than silently returning null, so a typo in a workflow's config is caught immediately when that node runs.

Using expressions from a custom node

Node config is resolved for you before your node's handle() runs — by the time you receive $config, every {{ }} expression in it has already been evaluated (see Custom Nodes). Inside handle(), WorkflowContext also exposes the same dot-notation resolution directly if you need to read something outside your node's own $config:

public function handle(WorkflowContext $context, array $config): NodeResult
{
$email = $context->get('trigger.email');
$default = $context->get('trigger.plan', 'free'); // with a fallback
// ...
}

$context->set('key.path', $value) and $context->forget('key.path') write to the context the same way — this is what the built-in Variable nodes use.

Next

  • Built-in Nodes — see each node's config fields for where expressions are commonly used.
  • Custom Nodes — building your own nodes.