Expression Language
Any string field on a node can mix plain text with expressions: {{ ... }} blocks that run JavaScript against the current workflow data. An expression editor shows autocomplete for the built-in variables below and a live preview of the result, evaluated against the node's last "Execute step" run.
Hello {{ $json.name }}, you have {{ $json.count }} new orders.
If the field is a single {{ ... }} block with nothing else around it, its evaluated value keeps its real type (number, object, array) instead of being converted to a string.
Built-in variables
| Variable | What it gives you |
|---|---|
$json | The current item's data — the main thing most expressions read. |
$node["Node Name"] | That node's output, for reaching back further than the immediately preceding node. |
$items() | Every item produced by the current node's input, as an array. |
$input | The raw input passed into the current node. |
$workflow | Workflow-level info: id, name, active version. |
$execution | The current run: id, mode, start time. |
$env | Environment variables your workspace has explicitly allow-listed. There is no passthrough to the host's own environment. |
$vars | Workflow Variables, set per workspace. |
$now / $today | The current date/time, as a Luxon DateTime — see below. |
Older ${...} expressions still work
FluidGrids originally shipped a simpler ${output.field}-style template (scopes: output, TriggerInput, WorkflowState, RunContext, item). Workflow versions saved with that syntax keep running exactly as before — {{ }} is a separate, additive expression language, not a replacement that breaks old versions.
Dates with Luxon
$now and $today are Luxon DateTime objects, so the usual Luxon methods are available:
{{ $now.plus({ days: 7 }).toISODate() }}
{{ $today.toFormat('yyyy-MM-dd') }}
Querying data with JMESPath
For reaching into a nested structure without writing a chain of .map()/.filter(), call $jmespath(data, query):
{{ $jmespath($json.orders, "[?status=='paid'].total") }}
See the JMESPath specification for query syntax.
Helper methods
Values carry a small set of extra, n8n-style helper methods on top of normal JavaScript:
| Type | Methods |
|---|---|
| String | .isEmpty(), .isNotEmpty(), .extractEmail(), .extractDomain(), .toDateTime() |
| Array | .isEmpty(), .isNotEmpty(), .chunk(size), .pluck(key), .unique() |
| Object | .isEmpty(), .isNotEmpty() |
{{ $json.email.extractDomain() }}
{{ $json.tags.isEmpty() ? 'untagged' : $json.tags.pluck('label') }}
Sandboxing
Expressions run in an isolated evaluator with no access to the host filesystem, network, or process — only the built-in variables and helper methods above are reachable.
What's not here yet
Per-item lineage ($("Node Name").item resolving to the specific upstream item a value traces back to, and a Code node "run once per item" mode) needs the executor to dispatch per item rather than per combined batch. That is tracked separately as the per-item execution model work.