n8n Expressions Cheatsheet: Transform Data Without Code Nodes
Your n8n workflow just failed because of a missing period. Or maybe a bracket in the wrong place. Perhaps you tried accessing a field that does not exist. These tiny syntax mistakes cause hours of frustration for n8n users every day.
The fix usually takes 30 seconds once you know what to look for. This cheatsheet gives you that knowledge.
The Expression Problem
Data transformation is the single most common struggle in n8n workflows. You receive data from one API in a certain format. The next node expects it in a different format. Somewhere in between, you need to extract, combine, or reshape that data.
The n8n expressions system handles these transformations without writing JavaScript code. You can access fields, manipulate strings, format dates, and filter arrays using simple inline syntax. But the documentation is scattered, and finding the right syntax for your specific use case means searching through forums and Stack Overflow posts.
Expressions vs Code Nodes
Before diving into syntax, understand when each approach makes sense.
| Task | Use Expression | Use Code Node |
|---|---|---|
| Access a single field | Yes | No |
| Simple string formatting | Yes | No |
| Combine two fields | Yes | No |
| Complex loops with conditions | No | Yes |
| Transform array structure | Maybe | Often |
| Multiple items to single item | No | Yes |
| Quick math calculation | Yes | No |
| API response restructuring | Depends | Often |
Rule of thumb: If your transformation fits in one line and does not require loops, use an expression. If you need multiple steps, variables, or complex logic, use the Code node.
What You’ll Learn
- Core expression syntax and all available built-in variables
- How to navigate nested JSON objects and arrays
- Working with multiple items using
.all(),.first(), and.last() - Complete reference tables for string, number, date, and array methods
- Conditional logic with ternary operators and null handling
- Common expression errors and how to fix them
- Decision framework for choosing expressions vs Code nodes
Expression Fundamentals
Every n8n expression lives inside double curly braces: {{ expression }}. When n8n executes your workflow, it evaluates these expressions and replaces them with the resulting values.
You can add expressions to almost any field in n8n. Click on a field, then click the Expression tab in the right panel. The expression editor provides autocomplete suggestions as you type, helping you discover available methods and variables.
Understanding Data Flow
Data flows through n8n workflows as items. Each item contains a json property holding the actual data. When you access $json.name, you are reading the name property from the current item’s JSON payload.
This distinction matters because some methods operate on items while others operate on the JSON data inside items.
Built-in Variables Reference
n8n provides several global variables for accessing data throughout your workflow.
| Variable | Purpose | Example |
|---|---|---|
$json | Current item’s JSON data | {{ $json.email }} |
$input | Input data with methods | {{ $input.first().json }} |
$('Node') | Access data from named node | {{ $('HTTP Request').item.json }} |
$node | Current node metadata | {{ $node.name }} |
$workflow | Workflow information | {{ $workflow.id }} |
$execution | Current execution data | {{ $execution.id }} |
$now | Current date and time | {{ $now.toISO() }} |
$today | Today’s date at midnight | {{ $today }} |
$runIndex | Current run index in loop | {{ $runIndex }} |
$itemIndex | Current item’s index | {{ $itemIndex }} |
The most commonly used variable is $json. Start there when building expressions.
Navigating JSON Data
Most expression work involves pulling values from JSON structures. Master these patterns and you will handle 80% of data transformation tasks.
Accessing Properties
Use dot notation to access object properties.
// Input: { "name": "John", "email": "[email protected]" }
{{ $json.name }} // Returns: John
{{ $json.email }} // Returns: [email protected]
Nested Objects
Chain dot notation for nested structures.
// Input: { "user": { "address": { "city": "Austin", "zip": "78701" } } }
{{ $json.user.address.city }} // Returns: Austin
{{ $json.user.address.zip }} // Returns: 78701
Bracket Notation
Use brackets when property names contain special characters or spaces.
// Input: { "first-name": "Jane", "Order ID": 12345 }
{{ $json['first-name'] }} // Returns: Jane
{{ $json['Order ID'] }} // Returns: 12345
Array Access
Access array elements by index. Arrays are zero-indexed.
// Input: { "items": ["apple", "banana", "cherry"] }
{{ $json.items[0] }} // Returns: apple
{{ $json.items[1] }} // Returns: banana
{{ $json.items[2] }} // Returns: cherry
Arrays of Objects
Combine array indexing with dot notation.
// Input: { "orders": [{ "id": 1, "total": 99 }, { "id": 2, "total": 149 }] }
{{ $json.orders[0].id }} // Returns: 1
{{ $json.orders[0].total }} // Returns: 99
{{ $json.orders[1].total }} // Returns: 149
Safe Navigation
When a property might not exist, use optional chaining to avoid errors.
// If address might be undefined:
{{ $json.user?.address?.city }} // Returns: undefined (no error)
// Without optional chaining, this would throw an error
JMESPath for Complex Queries
For advanced JSON querying, n8n supports JMESPath. Use $jmespath() for complex extractions.
// Extract all order totals from an array
{{ $jmespath($json, "orders[*].total") }} // Returns: [99, 149]
// Get first and last names as pairs
{{ $jmespath($json.people, "[].[first, last]") }}
JMESPath becomes valuable when you need to filter, project, or reshape deeply nested data structures without resorting to Code nodes.
Working with Multiple Items
Understanding how n8n handles multiple items is critical for building reliable workflows. Many expression errors stem from confusion about item context.
Item Methods
The $input variable provides methods for accessing items from the previous node.
| Method | Returns | Use Case |
|---|---|---|
$input.all() | All items as array | Process entire dataset |
$input.first() | First item only | Get initial record |
$input.last() | Last item only | Get final record |
$input.item | Current item | Default in most contexts |
Practical Examples
// Get all items from previous node
{{ $input.all() }}
// Get JSON from first item only
{{ $input.first().json }}
// Get email from last item
{{ $input.last().json.email }}
// Current item's data (implicit in most nodes)
{{ $json.name }} // Same as $input.item.json.name
Accessing Other Nodes
Use the $() function to pull data from any executed node in your workflow.
// Get data from a node named "HTTP Request"
{{ $('HTTP Request').item.json }}
// Get first item from "Webhook" node
{{ $('Webhook').first().json.body }}
// Get all items from "Google Sheets" node
{{ $('Google Sheets').all() }}
// Check if a node has executed
{{ $('Some Node').isExecuted }}
The node name must match exactly, including spaces and capitalization.
Item Linking
When processing data across multiple nodes, n8n maintains links between input and output items. The pairedItem property tracks which input item produced each output.
// Access the paired input item
{{ $input.item.pairedItem }}
This becomes important in complex workflows where you need to trace data lineage.
String Transformation Reference
String manipulation is the most common expression task. These methods work on any string value.
Core String Methods
| Method | Description | Example | Result |
|---|---|---|---|
.toUpperCase() | Convert to uppercase | {{ "hello".toUpperCase() }} | HELLO |
.toLowerCase() | Convert to lowercase | {{ "HELLO".toLowerCase() }} | hello |
.trim() | Remove leading/trailing whitespace | {{ " text ".trim() }} | text |
.trimStart() | Remove leading whitespace | {{ " text".trimStart() }} | text |
.trimEnd() | Remove trailing whitespace | {{ "text ".trimEnd() }} | text |
Searching and Testing
| Method | Description | Example | Result |
|---|---|---|---|
.includes(str) | Check if contains substring | {{ "hello world".includes("world") }} | true |
.startsWith(str) | Check if starts with | {{ "hello".startsWith("he") }} | true |
.endsWith(str) | Check if ends with | {{ "hello".endsWith("lo") }} | true |
.indexOf(str) | Find position of substring | {{ "hello".indexOf("l") }} | 2 |
Extracting and Slicing
| Method | Description | Example | Result |
|---|---|---|---|
.slice(start, end) | Extract substring | {{ "hello".slice(0, 3) }} | hel |
.substring(start, end) | Extract substring | {{ "hello".substring(1, 4) }} | ell |
.charAt(index) | Get character at position | {{ "hello".charAt(0) }} | h |
.split(delimiter) | Split into array | {{ "a,b,c".split(",") }} | [“a”,“b”,“c”] |
Replacing and Combining
| Method | Description | Example | Result |
|---|---|---|---|
.replace(old, new) | Replace first occurrence | {{ "hello".replace("l", "L") }} | heLlo |
.replaceAll(old, new) | Replace all occurrences | {{ "hello".replaceAll("l", "L") }} | heLLo |
.concat(str) | Combine strings | {{ "hello".concat(" world") }} | hello world |
.repeat(n) | Repeat string | {{ "ab".repeat(3) }} | ababab |
n8n-Specific String Methods
n8n adds custom data transformation functions beyond standard JavaScript.
| Method | Description | Example |
|---|---|---|
.extractEmail() | Extract email from text | {{ "Contact me at [email protected]".extractEmail() }} |
.extractUrl() | Extract URL from text | {{ "Visit https://example.com today".extractUrl() }} |
.extractDomain() | Get domain from URL | {{ "https://sub.example.com/path".extractDomain() }} |
.isEmail() | Check if valid email | {{ "[email protected]".isEmail() }} |
.isEmpty() | Check if empty/null | {{ "".isEmpty() }} |
.isNotEmpty() | Check if not empty | {{ "text".isNotEmpty() }} |
.base64Encode() | Encode as base64 | {{ "hello".base64Encode() }} |
.base64Decode() | Decode from base64 | {{ "aGVsbG8=".base64Decode() }} |
.hash(algorithm) | Generate hash | {{ "text".hash("sha256") }} |
.toTitleCase() | Title Case Text | {{ "hello world".toTitleCase() }} |
.toSentenceCase() | Sentence case text | {{ "HELLO WORLD".toSentenceCase() }} |
.toSnakeCase() | snake_case_text | {{ "Hello World".toSnakeCase() }} |
.removeMarkdown() | Strip markdown formatting | {{ "**bold** text".removeMarkdown() }} |
String Concatenation
Combine strings and variables using the + operator or template literals.
// Using + operator
{{ $json.firstName + " " + $json.lastName }}
// Building URLs
{{ "https://api.example.com/users/" + $json.userId }}
// Combining with static text
{{ "Order #" + $json.orderId + " confirmed" }}
Number and Math Operations
Perform calculations directly in expressions without Code nodes.
Basic Arithmetic
// Addition
{{ $json.price + $json.tax }}
// Subtraction
{{ $json.total - $json.discount }}
// Multiplication
{{ $json.quantity * $json.unitPrice }}
// Division
{{ $json.total / $json.items }}
// Modulo (remainder)
{{ $json.number % 2 }} // 0 if even, 1 if odd
Type Conversion
| Method | Description | Example |
|---|---|---|
.toInt() | Convert to integer | {{ "42".toInt() }} |
.toFloat() | Convert to float | {{ "3.14".toFloat() }} |
Number() | JavaScript conversion | {{ Number($json.value) }} |
Rounding Methods
// Round to nearest integer
{{ Math.round(3.7) }} // Returns: 4
// Round down
{{ Math.floor(3.9) }} // Returns: 3
// Round up
{{ Math.ceil(3.1) }} // Returns: 4
// Round to decimal places
{{ (3.14159).toFixed(2) }} // Returns: "3.14"
Practical Calculations
// Calculate percentage
{{ ($json.completed / $json.total * 100).toFixed(1) + "%" }}
// Currency formatting
{{ "$" + $json.amount.toFixed(2) }}
// Calculate order total with tax
{{ ($json.subtotal * 1.08).toFixed(2) }}
// Get absolute value
{{ Math.abs($json.difference) }}
// Find min/max
{{ Math.min($json.a, $json.b) }}
{{ Math.max($json.a, $json.b) }}
Date and Time Expressions
Date manipulation is essential for scheduling, filtering, and formatting workflows.
Current Date and Time
// Current datetime in ISO format
{{ $now.toISO() }} // Returns: 2025-12-14T10:30:00.000Z
// Current date only (midnight)
{{ $today }}
// Formatted current date
{{ $now.toLocaleString() }} // Returns: 12/14/2025, 10:30:00 AM
Date Formatting
// ISO 8601 format (API standard)
{{ $now.toISO() }}
// Just the date part
{{ $now.toISODate() }} // Returns: 2025-12-14
// Custom formatting with toFormat()
{{ $now.toFormat("yyyy-MM-dd") }} // 2025-12-14
{{ $now.toFormat("MM/dd/yyyy") }} // 12/14/2025
{{ $now.toFormat("MMMM d, yyyy") }} // December 14, 2025
{{ $now.toFormat("HH:mm:ss") }} // 14:30:00
{{ $now.toFormat("h:mm a") }} // 2:30 PM
Date Arithmetic
// Add days
{{ $now.plus({ days: 7 }).toISO() }}
// Subtract days
{{ $now.minus({ days: 30 }).toISO() }}
// Add hours
{{ $now.plus({ hours: 2 }).toISO() }}
// Complex additions
{{ $now.plus({ months: 1, days: 15 }).toISO() }}
Parsing Dates
// Parse date string to DateTime
{{ DateTime.fromISO($json.date) }}
// Parse specific format
{{ DateTime.fromFormat($json.date, "MM/dd/yyyy") }}
// Unix timestamp to DateTime
{{ DateTime.fromMillis($json.timestamp) }}
{{ DateTime.fromSeconds($json.unixTime) }}
Date Comparisons
// Check if date is in the past
{{ DateTime.fromISO($json.dueDate) < $now }}
// Check if date is today
{{ DateTime.fromISO($json.date).hasSame($today, 'day') }}
// Get difference in days
{{ $now.diff(DateTime.fromISO($json.startDate), 'days').days }}
Practical Date Examples
// Calculate age from birthdate
{{ Math.floor($now.diff(DateTime.fromISO($json.birthDate), 'years').years) }}
// Format for display
{{ DateTime.fromISO($json.createdAt).toFormat("MMM d, yyyy 'at' h:mm a") }}
// Get start of current month
{{ $now.startOf('month').toISO() }}
// Get end of current week
{{ $now.endOf('week').toISO() }}
// Check if within last 24 hours
{{ DateTime.fromISO($json.timestamp) > $now.minus({ hours: 24 }) }}
Array Transformations
Array methods let you filter, transform, and aggregate data without Code nodes.
Core Array Methods
| Method | Description | Example |
|---|---|---|
.length | Get array length | {{ $json.items.length }} |
.includes(value) | Check if contains value | {{ $json.tags.includes("urgent") }} |
.indexOf(value) | Find position of value | {{ $json.items.indexOf("apple") }} |
.join(separator) | Join into string | {{ $json.names.join(", ") }} |
.reverse() | Reverse order | {{ $json.items.reverse() }} |
.slice(start, end) | Extract portion | {{ $json.items.slice(0, 5) }} |
Filtering Arrays
// Filter with arrow function
{{ $json.orders.filter(order => order.status === "pending") }}
// Filter by numeric condition
{{ $json.products.filter(p => p.price > 100) }}
// Filter empty values
{{ $json.emails.filter(email => email && email.length > 0) }}
Transforming Arrays
// Extract single property from objects
{{ $json.users.map(user => user.email) }}
// Transform each element
{{ $json.prices.map(price => price * 1.1) }}
// Create new object structure
{{ $json.items.map(item => ({ name: item.title, cost: item.price })) }}
Finding Elements
// Find first matching element
{{ $json.users.find(user => user.id === 123) }}
// Find index of matching element
{{ $json.items.findIndex(item => item.name === "target") }}
// Check if any element matches
{{ $json.orders.some(order => order.total > 1000) }}
// Check if all elements match
{{ $json.tasks.every(task => task.completed === true) }}
Aggregation
// Sum all values
{{ $json.amounts.reduce((sum, val) => sum + val, 0) }}
// Count matching items
{{ $json.orders.filter(o => o.status === "shipped").length }}
// Get unique values
{{ [...new Set($json.categories)] }}
n8n-Specific Array Methods
// Remove duplicates (n8n built-in)
{{ $json.items.removeDuplicates() }}
// Remove duplicates by key
{{ $json.users.removeDuplicates("email") }}
// Pluck single property
{{ $json.users.pluck("name") }}
// Sort array
{{ $json.numbers.sort() }}
// Sort by property
{{ $json.users.sort("lastName") }}
Conditional Logic
Handle different scenarios with conditional expressions.
Ternary Operator
The ternary operator provides inline if/else logic.
// Basic condition
{{ $json.status === "active" ? "Yes" : "No" }}
// With field access
{{ $json.total > 100 ? "Free Shipping" : "$9.99 Shipping" }}
// Nested conditions
{{ $json.role === "admin" ? "Full Access" : $json.role === "user" ? "Limited Access" : "No Access" }}
Null Handling
// Nullish coalescing (use default if null/undefined)
{{ $json.nickname ?? $json.name }}
// Or operator (use default if falsy)
{{ $json.description || "No description provided" }}
// Optional chaining with fallback
{{ $json.user?.email ?? "[email protected]" }}
Combining Conditions
// AND condition
{{ $json.active && $json.verified ? "Ready" : "Pending" }}
// OR condition
{{ $json.premium || $json.trial ? "Has Access" : "No Access" }}
// Complex conditions
{{ ($json.type === "order" && $json.total > 50) ? "Priority" : "Standard" }}
Empty Checks
// Check if array is empty
{{ $json.items.length === 0 ? "No items" : $json.items.length + " items" }}
// Check if string is empty
{{ $json.notes.length > 0 ? $json.notes : "No notes" }}
// Using n8n methods
{{ $json.value.isEmpty() ? "Empty" : $json.value }}
Practical Patterns
// Status badge text
{{ $json.status === "completed" ? "Done" : $json.status === "pending" ? "Waiting" : "In Progress" }}
// Dynamic greeting
{{ $now.hour < 12 ? "Good morning" : $now.hour < 18 ? "Good afternoon" : "Good evening" }}
// Format price with currency
{{ $json.currency === "EUR" ? "€" : "$" }}{{ $json.amount.toFixed(2) }}
// Pluralization
{{ $json.count === 1 ? "1 item" : $json.count + " items" }}
Common Errors and Solutions
These expression errors appear constantly in the n8n community forums. Here is how to fix them.
Error Reference Table
| Error | Common Cause | Solution |
|---|---|---|
| ”Can’t get data for expression” | Node not executed yet | Ensure referenced node runs before current node |
| ”Referenced node is unexecuted” | Node skipped in execution path | Check workflow branching and execution order |
| ”Cannot read properties of undefined” | Accessing property on null/undefined | Use optional chaining: $json.user?.email |
| ”Invalid syntax” | Typo or trailing character | Check for trailing periods, missing brackets |
| ”Invalid JSON output” | Expression returns undefined | Verify data exists before accessing |
| ”Expression evaluated to null” | Source field is empty | Add fallback: $json.value ?? "default" |
Debugging Steps
Step 1: Check Data Structure
Click on the previous node and examine the output. Your expression must match the actual JSON structure, including correct property names and nesting levels.
Step 2: Verify Node Execution Order
The node you reference with $('NodeName') must execute before the current node. Check your workflow connections. If using branches, ensure the referenced node is in the execution path.
Step 3: Test Incrementally
Build expressions piece by piece.
// Start simple
{{ $json }}
// Add one level
{{ $json.user }}
// Add next level
{{ $json.user.address }}
// Final expression
{{ $json.user.address.city }}
Step 4: Use the Expression Editor
The expression editor shows real-time previews. If the preview shows an error or undefined, fix the expression before saving.
For persistent issues, use our free n8n workflow debugger to analyze error messages and get specific fixes.
Preventing Common Mistakes
// Bad: Accessing potentially undefined property
{{ $json.response.data.items[0].name }}
// Good: Safe navigation with fallbacks
{{ $json.response?.data?.items?.[0]?.name ?? "Unknown" }}
// Bad: Assuming data always exists
{{ $('HTTP Request').item.json.results }}
// Good: Check node executed first
{{ $('HTTP Request').isExecuted ? $('HTTP Request').item.json.results : [] }}
Expressions vs Code Node: When to Use Each
This decision matrix helps you choose the right approach.
Use Expressions When
- Accessing or extracting single fields
- Simple string formatting (uppercase, trim, concatenate)
- Basic math operations on individual values
- Date formatting or simple arithmetic
- Ternary conditions for simple logic
- Quick property transformations
Example scenarios:
- Building a dynamic URL from fields
- Formatting a name field
- Calculating a total with tax
- Extracting an email from text
Use Code Node When
- Processing multiple items into a single item
- Complex array restructuring
- Multiple transformation steps that depend on each other
- Loops with break conditions
- Creating new items from scratch
- Calling external functions or complex calculations
- When expression becomes unreadable (too long, too nested)
Example scenarios:
- Aggregating order totals by customer
- Converting flat list to nested structure
- Complex data validation with multiple rules
- Building custom JSON structures from various sources
The Crossover Zone
Some tasks can go either way. For these, prefer expressions for simplicity but switch to Code when expressions become hard to read.
// Acceptable as expression
{{ $json.items.filter(i => i.active).map(i => i.name).join(", ") }}
// Consider Code node if adding more complexity
{{ $json.items
.filter(i => i.active && i.category === "electronics")
.map(i => ({ name: i.name.toUpperCase(), price: i.price * 1.1 }))
.sort((a, b) => a.price - b.price)
.slice(0, 10) }}
For workflow architecture guidance, see our n8n workflow best practices guide.
Frequently Asked Questions
Why does my expression work in one node but not another?
Expression context depends on which node is currently executing. The $json variable refers to the current node’s input, which changes as data flows through your workflow.
If your expression works in Node A but not Node B, check what data Node B actually receives. Click on Node B and examine the input panel. The structure might differ from Node A’s output, especially after filtering or transformation nodes.
Also verify that any nodes you reference with $('NodeName') have already executed before the current node runs.
How do I access data from a node that is not directly connected?
Use the $('NodeName') syntax to access any previously executed node.
// Access the Webhook node from anywhere in the workflow
{{ $('Webhook').first().json.body }}
// Get all items from an earlier HTTP Request
{{ $('HTTP Request').all() }}
The referenced node must be in the execution path and must complete before the current node runs. If the node might not always execute (due to branching), check with .isExecuted first.
What is the difference between $json and $input.item.json?
They typically return the same data, but with subtle differences.
$jsonis shorthand for the current item’s JSON data. It is the most common way to access input data.$input.item.jsonexplicitly references the current item from the input and then accesses its JSON property.
In most cases, use $json for simplicity. Use $input.item.json when you need to be explicit about item context or when working with item methods like .pairedItem.
Can I use JavaScript functions inside expressions?
Yes. n8n expressions support standard JavaScript string, array, and object methods, plus n8n’s custom data transformation functions.
// Standard JavaScript
{{ Math.round($json.value) }}
{{ $json.items.filter(i => i.active) }}
{{ Object.keys($json.data) }}
// n8n-specific methods
{{ $json.email.extractDomain() }}
{{ $json.items.removeDuplicates() }}
You cannot define new functions or use multi-line code in expressions. For that, use the Code node.
How do I handle null or missing values without errors?
Use optional chaining and nullish coalescing together.
// Optional chaining prevents errors on undefined properties
{{ $json.user?.address?.city }}
// Nullish coalescing provides a fallback for null/undefined
{{ $json.nickname ?? "Anonymous" }}
// Combined pattern
{{ $json.user?.preferences?.theme ?? "default" }}
// Check with isEmpty()
{{ $json.notes.isEmpty() ? "No notes available" : $json.notes }}
For arrays, check length before accessing elements:
{{ $json.items?.length > 0 ? $json.items[0].name : "No items" }}
Next Steps
You now have a complete reference for n8n expressions. Bookmark this page and return when you need specific syntax.
For more n8n guidance:
- HTTP Request Node Guide for making API calls
- Fix Timeout Errors for workflow performance
- Credential Management for secure authentication
- Workflow Best Practices for production-ready patterns
If your workflows need professional optimization, our n8n consulting services can help you build reliable, maintainable automations.