Expressions
Expressions let you dynamically reference data from upstream nodes inside any configuration field. They use a safe, sandboxed syntax so your workflows stay secure.
Basic Syntax
Expressions are wrapped in double curly braces. The most common variable is $json, which references the output of the immediately upstream node:
{{ $json.fieldName }}When the workflow runs, the expression is replaced with the actual value from the upstream node's output. For example, if the upstream node produced {"email": "user@example.com"}, then {{ $json.email }} resolves to user@example.com.
Secure expressions
Dot Notation for Nested Access
Use dot notation to access nested properties at any depth:
{{ $json.customer.name }}
{{ $json.customer.address.city }}
{{ $json.items[0].product.title }}
{{ $json.metadata.tags[2] }}Array elements are accessed with bracket notation using zero-based indices. You can chain dot and bracket notation freely.
Where Expressions Are Used
Most text-based configuration fields in the node panel support expressions. You can mix static text with expressions:
Hello {{ $json.customer.name }}, your order #{{ $json.orderId }} has shipped!| Field Type | Expression Support |
|---|---|
| Text inputs | Full support -- static text + expressions |
| URL fields | Full support |
| JSON body fields | Full support for values |
| Dropdown selects | Not supported -- use a fixed selection |
| Boolean toggles | Not supported -- use If/Else node instead |
Field Picker
You do not need to memorize field paths. The configuration panel includes a field picker that displays the output schema of the upstream node as a navigable tree. Click any field to insert the corresponding expression at the cursor position.
The field picker is available in any expression-enabled input. Click the {} icon next to the input field to open it.
Use the field picker
Live Preview
When you type an expression, the configuration panel shows a live preview of the resolved value beneath the input field. The preview uses the most recent test output from the upstream node, so you can see exactly what your expression will produce.
If the expression references a field that does not exist, the preview shows undefined and highlights the input with a warning. This helps catch errors before you run the workflow.
Expression Templates
Build complex strings by combining multiple expressions with static text. This is particularly useful for constructing API URLs, email bodies, or Slack messages:
# API endpoint with dynamic path
https://api.example.com/users/{{ $json.userId }}/orders/{{ $json.orderId }}
# Slack message
:white_check_mark: *{{ $json.customer.name }}* just placed order #{{ $json.orderId }} for ${{ $json.total }}
# SQL query
SELECT * FROM orders WHERE customer_id = '{{ $json.customerId }}' AND status = 'pending'SQL injection
Subflow Expressions
When a workflow runs as a subflow (invoked by a Subflow node in a parent workflow), the inputs passed by the parent are available through the $subflow variable:
{{ $subflow.contactEmail }}
{{ $subflow.companyName }}
{{ $subflow.options.sendNotification }}The $subflow variable contains only the inputs defined in the subflow's trigger configuration. It is separate from $json, which still refers to the upstream node's output within the subflow.
$json vs $subflow
$json refers to the previous node's output (as usual), while $subflow refers to the parameters passed from the parent workflow. They are independent and can be used together.Available Variables
| Variable | Description |
|---|---|
$json | Output of the immediately upstream node |
$subflow | Input parameters passed from a parent workflow (only available in subflows) |
$executionId | Unique identifier for the current workflow execution |
$timestamp | Current Unix timestamp in milliseconds |
$workflowId | Identifier of the current workflow |