n8n Expressions Cheatsheet: Transform Data Without Code Nodes
n8n Expressions Cheatsheet: Transform Data Without Code Nodes
• Logic Workflow Team

n8n Expressions Cheatsheet: Transform Data Without Code Nodes

#n8n #expressions #data transformation #tutorial #cheatsheet #no-code

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.

TaskUse ExpressionUse Code Node
Access a single fieldYesNo
Simple string formattingYesNo
Combine two fieldsYesNo
Complex loops with conditionsNoYes
Transform array structureMaybeOften
Multiple items to single itemNoYes
Quick math calculationYesNo
API response restructuringDependsOften

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.

VariablePurposeExample
$jsonCurrent item’s JSON data{{ $json.email }}
$inputInput data with methods{{ $input.first().json }}
$('Node')Access data from named node{{ $('HTTP Request').item.json }}
$nodeCurrent node metadata{{ $node.name }}
$workflowWorkflow information{{ $workflow.id }}
$executionCurrent execution data{{ $execution.id }}
$nowCurrent date and time{{ $now.toISO() }}
$todayToday’s date at midnight{{ $today }}
$runIndexCurrent run index in loop{{ $runIndex }}
$itemIndexCurrent item’s index{{ $itemIndex }}

The most commonly used variable is $json. Start there when building expressions.

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.

MethodReturnsUse Case
$input.all()All items as arrayProcess entire dataset
$input.first()First item onlyGet initial record
$input.last()Last item onlyGet final record
$input.itemCurrent itemDefault 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

MethodDescriptionExampleResult
.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

MethodDescriptionExampleResult
.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

MethodDescriptionExampleResult
.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

MethodDescriptionExampleResult
.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.

MethodDescriptionExample
.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

MethodDescriptionExample
.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

MethodDescriptionExample
.lengthGet 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

ErrorCommon CauseSolution
”Can’t get data for expression”Node not executed yetEnsure referenced node runs before current node
”Referenced node is unexecuted”Node skipped in execution pathCheck workflow branching and execution order
”Cannot read properties of undefined”Accessing property on null/undefinedUse optional chaining: $json.user?.email
”Invalid syntax”Typo or trailing characterCheck for trailing periods, missing brackets
”Invalid JSON output”Expression returns undefinedVerify data exists before accessing
”Expression evaluated to null”Source field is emptyAdd 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.

  • $json is shorthand for the current item’s JSON data. It is the most common way to access input data.
  • $input.item.json explicitly 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:

If your workflows need professional optimization, our n8n consulting services can help you build reliable, maintainable automations.

Ready to Automate Your Business?

Tell us what you need automated. We'll build it, test it, and deploy it fast.

âś“ 48-72 Hour Turnaround
âś“ Production Ready
âś“ Free Consultation
⚡

Create Your Free Account

Sign up once, use all tools free forever. We require accounts to prevent abuse and keep our tools running for everyone.

or

By signing up, you agree to our Terms of Service and Privacy Policy. No spam, unsubscribe anytime.