n8n's expression system is what separates simple automations from truly dynamic, data-driven workflows. The {{ }} syntax gives you access to data from any previous node, built-in variables, JavaScript functions, and environment configuration — all inline, without a separate Code node. Mastering expressions unlocks the full power of n8n. This guide is a complete reference you can bookmark and return to.
Wrap any expression in double curly braces: {{ your expression here }}. Everything inside is evaluated as JavaScript. You can reference n8n variables, use string methods, do arithmetic, call ternary operators, and chain operations. Outside the braces is treated as literal text.
Expression Syntax Fundamentals
Expressions can appear in any text field in n8n — node parameters, headers, URLs, message bodies, and more. Toggle a field to expression mode by clicking the bolt icon (⚡) next to any input field, or by typing {{.
Literal vs expression mixing
Click the bolt icon ⚡ on any field to open the full Expression Editor. It provides autocomplete for all built-in variables, a live preview showing the resolved value with your actual current data, and syntax highlighting. Use it when building complex expressions — much easier than guessing.
$json — Accessing Current Node Data
$json refers to the JSON data of the current item being processed. It's the most commonly used variable in n8n.
$node — Data from Any Previous Node
$node gives you access to the output of any named node in your workflow, not just the immediately previous one. This is essential when you need data from several steps back.
$node["Get Customer"] and $node["get customer"] are different. Always match the exact node name as it appears on the canvas. Rename your nodes to descriptive names before referencing them — "HTTP Request3" is a poor reference target.
$items — All Items from a Node
$items() returns the complete array of all items output by a node — not just the current item. Use this when you need to aggregate or compare across all items.
Built-in Variables: $now, $today, $workflow, $execution
n8n provides a set of built-in variables you can use in any expression without referencing a node.
Date and time variables
| Variable | Description | Example Output |
|---|---|---|
| $now | Current datetime as a Luxon DateTime object | 2026-03-13T08:00:00.000Z |
| $today | Start of today (midnight) as Luxon DateTime | 2026-03-13T00:00:00.000Z |
| $now.toISO() | ISO 8601 string | "2026-03-13T08:00:00.000Z" |
| $now.toISODate() | Date only string | "2026-03-13" |
| $now.toFormat('dd/MM/yyyy') | Custom format string | "13/03/2026" |
| $now.toFormat('h:mm a') | Time with AM/PM | "8:00 AM" |
| $now.plus({ days: 7 }).toISODate() | 7 days from now | "2026-03-20" |
| $now.minus({ hours: 24 }).toISO() | 24 hours ago | yesterday's datetime |
| $now.weekday | Day of week (1=Mon, 7=Sun) | 5 |
| $now.month | Month number | 3 |
| $now.year | Year | 2026 |
| $now.toMillis() | Unix timestamp in ms | 1741863600000 |
Workflow and execution variables
| Variable | Description | Example Output |
|---|---|---|
| $workflow.id | Unique workflow ID | "abc123" |
| $workflow.name | Workflow name | "Morning Weather Alert" |
| $workflow.active | Whether workflow is activated | true |
| $execution.id | Unique ID of current execution | "ex_xyz789" |
| $execution.mode | "manual" or "trigger" | "trigger" |
| $execution.resumeUrl | URL to resume a waiting execution | https://... |
| $itemIndex | Index of the current item being processed | 0 |
| $runIndex | Current run index (for retried nodes) | 0 |
JavaScript in Expressions
Everything inside {{ }} is JavaScript. You can use the full JavaScript standard library — string methods, array operations, math, regex, Date, JSON, and more.
String operations
Number and math operations
Array and object operations
Conditional Expressions
Use JavaScript ternary operators and nullish coalescing for conditional logic directly in expressions:
Environment Variables in n8n
For configuration values that shouldn't be hardcoded in workflows (API keys, base URLs, feature flags), use n8n's built-in variable system.
n8n Variables (Settings → Variables)
Added in n8n 0.225, this is the recommended way to store reusable values without environment access:
System environment variables (self-hosted only)
Static Data: Persisting Values Between Executions
n8n provides a per-workflow key-value store called static data. Unlike regular variables, values stored here persist between executions — useful for tracking state, counters, or last-run timestamps.
Common Expression Patterns
These patterns solve the most frequent expression use cases in real workflows:
Date formatting for different APIs
Building dynamic URLs and query strings
Handling null and undefined safely
Using the Expression Editor Effectively
The Expression Editor (accessible via the ⚡ bolt icon on any field) is your best friend for building complex expressions. Key features:
- Live preview: Shows the resolved value of your expression using actual data from the last execution or pinned data. If the preview shows
[undefined], the path is wrong. - Autocomplete: Type
$to see all available variables. Type$json.to see all available fields from your current data. - Syntax highlighting: Makes complex expressions readable.
- Error messages: JavaScript syntax errors are shown inline.
- Data explorer: Browse incoming data structure in the left panel while building the expression.
Common Mistakes and How to Fix Them
1. "[undefined]" in output
2. Expression not evaluating (showing literal text)
3. TypeError on null access
4. Wrong data from $node reference
Frequently Asked Questions
async functions), or a dedicated integration node. Expressions are evaluated inline during node execution and cannot perform I/O.$json is a shorthand for $input.item.json — they refer to the same thing: the JSON data of the current item coming from the directly connected input node. Use $json for brevity. Use $input.item.json when you want to be explicit or when $json is ambiguous in a complex nested context.DateTime (from Luxon) is available in n8n expressions but only when accessed through $now, $today, or by constructing via DateTime.fromISO(). You do NOT need to import Luxon — it's pre-loaded. If DateTime is undefined in your expression, try $now.constructor.fromISO(dateString) as an alternative.$json.headers['content-type'] (object with header names as keys). Note: response headers are normalized to lowercase in n8n regardless of what the server sent.