Expressions
Expressions let you reference data from upstream nodes and transform it dynamically in any node's input field.
Syntax
Expressions use double curly brace syntax:
{{ expression }}
Inside the braces, you write standard JavaScript (ES6+).
Inline expressions
You can embed expressions inside string fields:
Hello, {{ $json['get_user'].name }}! Your order #{{ $json['http_trigger'].request.path_params.orderId }} is ready.
Full expression
If the entire field value is an expression, the result replaces the whole value (including non-string types):
{{ $json['get_orders'].response.body.items.length }}
This would produce a number, not a string.
The $json context
$json is the global data object available in every node. It contains the output of every previously executed node, keyed by node ID.
$json['node_id'] → output of a specific node
$json['http_trigger'] → always the incoming request data
Accessing request data
The http_trigger node always has this structure:
$json['http_trigger'].request.method // "GET", "POST", etc.
$json['http_trigger'].request.path // "/payments/transactions"
$json['http_trigger'].request.path_params.id // path parameter {id}
$json['http_trigger'].request.query.limit // query string ?limit=10
$json['http_trigger'].request.headers['authorization']
$json['http_trigger'].request.body // parsed request body
$json['http_trigger'].request.body.user.email
A manual_trigger node (runs started from the workflow builder) uses your node id as the key and only provides:
$json['m1'].triggered_at // RFC3339 timestamp
$json['m1'].trigger // "manual"
Accessing node outputs
For an http_request_node with ID fetch_order:
$json['fetch_order'].response.status_code // 200
$json['fetch_order'].response.headers // response headers object
$json['fetch_order'].response.body // parsed response body
$json['fetch_order'].response.body.orderId // nested field
For a mongodb_node with ID get_customer:
$json['get_customer'].document // found document
$json['get_customer'].document.name
$json['get_customer'].count // for find operations
$json['get_customer'].documents // for find (multiple)
For a set_node with ID prepare_data:
$json['prepare_data'].result // whatever you set
$json['prepare_data'].result.user
JavaScript in expressions
Full ES6+ JavaScript is supported inside expressions:
// Ternary
{{ $json['http_trigger'].request.query.limit ? parseInt($json['http_trigger'].request.query.limit) : 20 }}
// Array methods
{{ $json['get_orders'].response.body.items.filter(o => o.status === 'pending').length }}
// String methods
{{ $json['get_user'].response.body.name.toUpperCase() }}
// Math
{{ Math.round($json['calculate'].total * 100) / 100 }}
// JSON serialization
{{ JSON.stringify($json['prepare_data'].result) }}
// Date
{{ new Date().toISOString() }}
Examples
URL with path parameter
https://api.example.com/users/{{ $json['http_trigger'].request.path_params.userId }}/profile
Conditional header
{{ $json['http_trigger'].request.headers['x-forwarded-for'] || $json['http_trigger'].request.headers['x-real-ip'] }}
Response body from upstream call
{{ JSON.stringify({
user: $json['get_user'].response.body,
balance: $json['get_balance'].response.body.amount
}) }}
MongoDB filter
{ "userId": "{{ $json['http_trigger'].request.path_params.userId }}", "status": "active" }
Email subject
Order {{ $json['http_trigger'].request.path_params.orderId }} confirmed for {{ $json['get_user'].document.email }}
Loop variables (on $json)
When a node is part of a Loop Node body (connected from the loop), the engine adds iteration fields to the same $json object as everywhere else. Use bracket notation:
| Expression | Meaning |
|---|---|
$json['$item'] | Current element of the array being iterated |
$json['$index'] | Zero-based index in that array |
$json['$loop'] | Object { item, index, count } where count is total length |
Examples: {{ 'https://api.example.com/items/' + $json['$item'] }}, {{ $json['$loop'].count }}.
You can still use $json['node_id'] for upstream nodes. The loop node’s own output after completion includes results (per-iteration outputs) and count (also available on $json['<loop_node_id>'] depending on your graph).
Tips
- Node IDs matter: when you add a node, it gets an auto-generated ID. Click the node to see or change its ID. Use descriptive IDs like
get_user,fetch_orderfor readable expressions. - Debug with code_node: use a
code_nodetoconsole.log($json)and inspect the full context during testing. - Validate early: use the workflow Validate button to catch expression errors before going live.
- JSON vs string: when a field expects JSON (like a database filter), use
{{ expression }}as the entire value rather than embedding it in a string.
Related docs
- Building Workflows — canvas editor, node wiring, and saving
- Node Reference — all available nodes and their fields