Expressions are the secret weapon of n8n power users.
They let you access data, transform values, and build dynamic workflows without writing code. But the syntax trips up everyone at first.
Here's everything you need to know about n8n expressions.
What Are Expressions?
Expressions are dynamic values enclosed in {{ }}. They're evaluated at runtime using data from previous nodes.
Instead of hardcoding:
```
Hello, John
```
You write:
```
Hello, {{ $json.firstName }}
```
And it becomes "Hello, John" when the workflow runs.
Basic Syntax
Accessing Current Node Data
```
{{ $json.fieldName }}
```
$json refers to the input data of the current node.
Nested Objects
```
{{ $json.user.profile.name }}
```
Arrays
```
{{ $json.items[0] }} // First item
{{ $json.items[0].name }} // First item's name
{{ $json.items.length }} // Number of items
```
Previous Node Data
```
{{ $('NodeName').item.json.field }}
```
Access data from any previous node by name.
Essential Variables
$json
The current item's data. Most commonly used.
```
{{ $json.email }}
{{ $json.order.total }}
```
$input
All input data to the current node.
```
{{ $input.first().json.field }} // First item
{{ $input.last().json.field }} // Last item
{{ $input.all() }} // All items as array
```
$('NodeName')
Reference a specific node's output.
```
{{ $('HTTP Request').item.json.data }}
{{ $('Get Users').first().json.users }}
```
$node
Current node information.
```
{{ $node.name }} // Current node's name
{{ $node.outputIndex }} // Which output (for multi-output nodes)
```
$workflow
Workflow metadata.
```
{{ $workflow.id }}
{{ $workflow.name }}
{{ $workflow.active }}
```
$execution
Current execution details.
```
{{ $execution.id }}
{{ $execution.mode }} // "manual" or "trigger"
{{ $execution.resumeUrl }} // For wait nodes
```
$now / $today
Date/time helpers.
```
{{ $now }} // Current datetime
{{ $today }} // Today at midnight
{{ $now.toISO() }} // ISO format string
{{ $now.minus({days: 7}) }} // 7 days ago
```
Data Type Conversions
To String
```
{{ String($json.number) }}
{{ $json.number.toString() }}
{{ $json.number + '' }}
```
To Number
```
{{ Number($json.string) }}
{{ parseInt($json.string) }}
{{ parseFloat($json.string) }}
{{ +$json.string }}
```
To Boolean
```
{{ Boolean($json.value) }}
{{ !!$json.value }}
```
To Array
```
{{ $json.string.split(',') }} // String to array
{{ Array.from($json.iterable) }} // Iterable to array
{{ [$json.item1, $json.item2] }} // Create array
```
String Operations
Concatenation
```
{{ $json.firstName + ' ' + $json.lastName }}
{{ \Hello, \${$json.name}!\ }}
```
Case Conversion
```
{{ $json.text.toLowerCase() }}
{{ $json.text.toUpperCase() }}
```
Trimming
```
{{ $json.text.trim() }}
{{ $json.text.trimStart() }}
{{ $json.text.trimEnd() }}
```
Substring
```
{{ $json.text.substring(0, 10) }} // First 10 chars
{{ $json.text.slice(-5) }} // Last 5 chars
```
Replace
```
{{ $json.text.replace('old', 'new') }}
{{ $json.text.replaceAll('old', 'new') }}
```
Split and Join
```
{{ $json.csv.split(',') }} // String to array
{{ $json.array.join(', ') }} // Array to string
```
Check Contents
```
{{ $json.text.includes('keyword') }}
{{ $json.text.startsWith('Hello') }}
{{ $json.text.endsWith('.com') }}
```
Array Operations
Accessing Elements
```
{{ $json.items[0] }} // First
{{ $json.items[$json.items.length - 1] }} // Last
```
Filtering
```
{{ $json.users.filter(u => u.active) }}
{{ $json.orders.filter(o => o.total > 100) }}
```
Mapping
```
{{ $json.users.map(u => u.email) }}
{{ $json.items.map(i => i.name.toUpperCase()) }}
```
Finding
```
{{ $json.users.find(u => u.id === 123) }}
{{ $json.items.findIndex(i => i.name === 'target') }}
```
Reducing
```
{{ $json.orders.reduce((sum, o) => sum + o.total, 0) }}
```
Checking
```
{{ $json.items.some(i => i.urgent) }} // Any match?
{{ $json.items.every(i => i.valid) }} // All match?
{{ $json.items.includes('value') }} // Contains value?
```
Sorting
```
{{ $json.items.sort() }} // Alphabetical
{{ $json.items.sort((a, b) => a.price - b.price) }} // By property
```
Date and Time
n8n uses Luxon for dates. Key operations:
Current Time
```
{{ $now }}
{{ $now.toISO() }}
{{ $now.toFormat('yyyy-MM-dd') }}
```
Formatting
```
{{ $now.toFormat('yyyy-MM-dd') }} // 2026-01-19
{{ $now.toFormat('HH:mm:ss') }} // 14:30:00
{{ $now.toFormat('MMMM d, yyyy') }} // January 19, 2026
{{ $now.toFormat('EEE') }} // Mon
```
Parsing Dates
```
{{ DateTime.fromISO($json.dateString) }}
{{ DateTime.fromFormat($json.date, 'MM/dd/yyyy') }}
```
Date Math
```
{{ $now.plus({days: 7}) }}
{{ $now.minus({hours: 2}) }}
{{ $now.startOf('day') }}
{{ $now.endOf('month') }}
```
Comparisons
```
{{ DateTime.fromISO($json.date) > $now }}
{{ $now.diff(DateTime.fromISO($json.date), 'days').days }}
```
Conditional Logic
Ternary Operator
```
{{ $json.status === 'active' ? 'Yes' : 'No' }}
{{ $json.count > 0 ? $json.items : [] }}
```
Nullish Coalescing
```
{{ $json.name ?? 'Unknown' }} // Use 'Unknown' if null/undefined
{{ $json.settings?.theme ?? 'light' }} // Safe navigation + default
```
Logical Operators
```
{{ $json.a && $json.b }} // Both truthy
{{ $json.a || $json.b }} // Either truthy
{{ !$json.deleted }} // Negation
```
Common Patterns
Safe Property Access
Avoid errors when properties might not exist:
```
{{ $json.user?.profile?.name ?? 'Guest' }}
```
Building URLs
```
{{ 'https://api.example.com/users/' + $json.userId }}
{{ \https://api.example.com/search?q=\${encodeURIComponent($json.query)}\ }}
```
Creating Objects
```
{{ { name: $json.firstName + ' ' + $json.lastName, email: $json.email } }}
```
Merging Objects
```
{{ { ...$json, status: 'processed' } }}
{{ Object.assign({}, $json.defaults, $json.overrides) }}
```
Extracting Unique Values
```
{{ [...new Set($json.items.map(i => i.category))] }}
```
Grouping Data
```
{{ $json.items.reduce((groups, item) => {
const key = item.category;
groups[key] = groups[key] || [];
groups[key].push(item);
return groups;
}, {}) }}
```
Expression Editor Tips
Use the Expression Editor
Click the gears icon next to any field. The expression editor shows:
- Available variables
- Autocomplete suggestions
- Real-time preview of results
Test with Real Data
Run your workflow once with a manual trigger. Then edit nodes — the expression editor shows actual data from the last run.
Copy Paths from Input
In the input panel, hover over a field and click the copy icon. It gives you the exact expression path.
Debugging Expressions
Common Errors
"Cannot read property 'x' of undefined"
The object doesn't exist. Use optional chaining:
```
{{ $json.response?.data?.items }}
```
"x is not a function"
You're calling a method on the wrong type. Check what you're actually getting:
```
{{ typeof $json.value }}
```
Expression returns [object Object]
You're trying to use an object as a string. Stringify it:
```
{{ JSON.stringify($json.data) }}
```
Debug with Set Node
Add a Set node to inspect values:
- Add Set node after the problem area
- Create a field with your expression
- Run and inspect the output
Performance Considerations
Expressions run on every item. Heavy operations can slow things down:
Avoid in Expressions
- Large array operations on every item
- Multiple HTTP calls (use nodes instead)
- Complex recursive functions
Better Patterns
- Pre-process data in earlier nodes
- Use Code node for complex transformations
- Filter data before processing
Real-World Examples
Format Currency
```
{{ '$' + $json.amount.toFixed(2) }}
```
Extract Domain from Email
```
{{ $json.email.split('@')[1] }}
```
Calculate Age from Birthdate
```
{{ Math.floor($now.diff(DateTime.fromISO($json.birthdate), 'years').years) }}
```
Generate Slug from Title
```
{{ $json.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') }}
```
Mask Credit Card
```
{{ '** ** ' + $json.cardNumber.slice(-4) }}
```
Check Business Hours
```
{{ $now.hour >= 9 && $now.hour < 17 && $now.weekday <= 5 }}
```
Ready to master expressions? Nodox.ai challenges push you to transform data in ways that build real expression skills. Learn by solving problems, not memorizing syntax.