Skip to main content

Expressions

Expressions allow you to dynamically transform and reference data in n8n workflows. They enable you to access data from previous nodes, use built-in functions, and create complex data transformations.

Expression Basics

Expressions in n8n are wrapped in double curly braces and start with an equals sign:
={{$json.fieldName}}
={{$node["NodeName"].json.data}}
={{new Date().toISOString()}}

When to Use Expressions

Expressions can be used in:
  • Node parameters (URLs, headers, body data)
  • Conditional logic (IF nodes, Switch nodes)
  • Data transformation (Set nodes, Code nodes)
  • Filter operations
  • Any string-type parameter

Expression Evaluation

The Expression class handles all expression evaluation in n8n:
// From expression.ts:180-181
export class Expression {
  constructor(private readonly workflow: Workflow) {}

  // Initialize secure sandbox environment
  static initializeGlobalContext(data: IDataObject) {
    // Denylist dangerous globals
    data.document = {};
    data.window = {};
    data.eval = {};
    data.Function = {};
    
    // Allowlist safe utilities
    data.Date = Date;
    data.DateTime = DateTime;    // Luxon DateTime
    data.Math = Math;
    data.JSON = JSON;
    data.Object = createSafeObject();  // Sanitized Object
  }
}
Expressions run in a sandboxed environment that blocks dangerous operations like eval(), Function(), fetch(), and access to window or document objects.

Data Access Patterns

Current Node Data

Access JSON data from the current item:
// Current item's data
{{$json.fieldName}}
{{$json.user.email}}
{{$json.items[0].id}}

// Nested access
{{$json.response.data.users[0].name}}

Previous Node Data

// Access data from a specific node
{{$node["HTTP Request"].json.userId}}
{{$node["Webhook"].json.body.email}}

// Access specific item from a node
{{$node["HTTP Request"].json[0].id}}

// Check if node has data
{{$node["HTTP Request"].json !== undefined}}

Multiple Items

When processing multiple items:
// Map over all items
{{$input.all().map(item => item.json.name)}}

// Filter items
{{$input.all().filter(item => item.json.age > 18)}}

// Reduce items
{{$input.all().reduce((sum, item) => sum + item.json.amount, 0)}}

Built-in Functions and Variables

Date and Time

// JavaScript Date
{{new Date()}}
{{new Date().toISOString()}}
{{Date.now()}}

// Luxon DateTime (recommended)
{{DateTime.now()}}
{{DateTime.now().toISO()}}
{{DateTime.now().toFormat('yyyy-MM-dd')}}

Math Operations

// Basic math
{{Math.round($json.price * 1.2)}}
{{Math.floor($json.value)}}
{{Math.max(...$input.all().map(i => i.json.score))}}

// Random numbers
{{Math.random()}}
{{Math.floor(Math.random() * 100)}}

String Operations

// String methods
{{$json.name.toUpperCase()}}
{{$json.email.toLowerCase()}}
{{$json.text.trim()}}
{{$json.description.substring(0, 100)}}

// Template literals
{{`Hello ${$json.name}, your order #${$json.orderId} is ready`}}

// String concatenation
{{$json.firstName + " " + $json.lastName}}

// Regular expressions
{{/\d{3}-\d{4}/.test($json.phone)}}
{{$json.text.replace(/\s+/g, '-')}}

Array Operations

// Array methods
{{$json.items.length}}
{{$json.items.map(i => i.id)}}
{{$json.items.filter(i => i.active)}}
{{$json.items.find(i => i.id === 123)}}
{{$json.items.some(i => i.quantity > 0)}}
{{$json.items.every(i => i.validated)}}

// Array manipulation
{{$json.items.slice(0, 5)}}
{{$json.items.concat($json.moreItems)}}
{{[...$json.items, newItem]}}

Object Operations

// Object methods
{{Object.keys($json)}}
{{Object.values($json)}}
{{Object.entries($json)}}

// Object manipulation
{{Object.assign({}, $json, {newField: 'value'})}}
{{{...$json, updatedField: 'new value'}}}

// Check properties
{{$json.hasOwnProperty('fieldName')}}
{{'fieldName' in $json}}

Workflow Data Proxy

The WorkflowDataProxy class provides access to workflow execution data:
// Available in expressions
const dataProxy = {
  $json: currentItem.json,
  $binary: currentItem.binary,
  $itemIndex: currentItemIndex,
  $node: nodeDataProxy,
  $input: inputProxy,
  $parameter: nodeParameters,
  $workflow: workflowMetadata,
  $execution: executionMetadata,
  $vars: environmentVariables,
  $env: environmentVariables  // Alias for $vars
};

Workflow Metadata

// Workflow information
{{$workflow.id}}
{{$workflow.name}}
{{$workflow.active}}

// Execution information
{{$execution.id}}
{{$execution.mode}}  // 'manual', 'trigger', 'webhook'
{{$execution.resumeUrl}}  // For wait nodes

Environment Variables

// Access environment variables
{{$env.API_KEY}}
{{$vars.DATABASE_URL}}

// Use in configurations
{{
  url: $env.API_ENDPOINT,
  headers: {
    'Authorization': `Bearer ${$env.API_TOKEN}`
  }
}}

Expression Security

Sandbox Protection

The expression sandbox prevents malicious code execution:
// From expression.ts:186-235
static initializeGlobalContext(data: IDataObject) {
  // Blocked: Remote code execution
  data.eval = {};
  data.Function = {};
  data.setTimeout = {};
  data.setInterval = {};

  // Blocked: Network requests
  data.fetch = {};
  data.XMLHttpRequest = {};

  // Blocked: Control flow
  data.Promise = {};
  data.Generator = {};
  data.AsyncFunction = {};

  // Blocked: Low-level access
  data.WebAssembly = {};
  data.Reflect = {};
  data.Proxy = {};

  // Allowed: Safe utilities
  data.Date = Date;
  data.DateTime = DateTime;
  data.Math = Math;
  data.JSON = JSON;
  data.Object = createSafeObject();  // Sanitized version
}
The safe Object wrapper blocks dangerous methods like defineProperty, setPrototypeOf, and __defineGetter__ that could bypass security checks.

Error Handling

Expressions can throw specific errors:
// From expression.ts:39-51
const isSyntaxError = (error: unknown): error is SyntaxError =>
  error instanceof SyntaxError || 
  (error instanceof Error && error.name === 'SyntaxError');

const isExpressionError = (error: unknown): error is ExpressionError =>
  error instanceof ExpressionError || 
  error instanceof ExpressionExtensionError;

const isTypeError = (error: unknown): error is TypeError =>
  error instanceof TypeError || 
  (error instanceof Error && error.name === 'TypeError');

Advanced Patterns

Conditional Expressions

// Ternary operator
{{$json.status === 'active' ? 'Active User' : 'Inactive User'}}

// Nullish coalescing
{{$json.description ?? 'No description provided'}}

// Logical OR for defaults
{{$json.count || 0}}
{{$json.name || 'Unknown'}}

// Complex conditions
{{
  $json.score >= 90 ? 'A' :
  $json.score >= 80 ? 'B' :
  $json.score >= 70 ? 'C' : 'F'
}}

Data Transformation

// Transform array of objects
{{
  $json.users.map(user => ({
    id: user.id,
    fullName: `${user.firstName} ${user.lastName}`,
    email: user.email.toLowerCase()
  }))
}}

// Aggregate data
{{
  $input.all().reduce((acc, item) => {
    const category = item.json.category;
    acc[category] = (acc[category] || 0) + item.json.amount;
    return acc;
  }, {})
}}

// Flatten nested arrays
{{$json.items.flatMap(item => item.tags)}}

Dynamic Node References

Expressions can reference nodes dynamically:
// Dynamic node name
{{$node[$json.sourceNode].json.data}}

// Conditional node reference
{{
  $json.useCache 
    ? $node["Cache"].json.result 
    : $node["API"].json.result
}}

Expression Extensions

Custom extensions can be added to expressions:
// From extensions/expression-extension.ts
import { extend, extendOptional } from './extensions';
import { extendSyntax } from './extensions/expression-extension';
import { extendedFunctions } from './extensions/extended-functions';

// Extend expression capabilities
extend(dataProxy, functions, methods);

Expression Best Practices

  1. Keep expressions simple: Complex logic belongs in Code nodes
  2. Use descriptive variable names: When using intermediate variables
  3. Handle null/undefined: Always check for data existence
  4. Use type-safe operations: Be aware of data types
  5. Avoid side effects: Expressions should be pure functions
  6. Test with sample data: Use the expression editor’s test mode
  7. Document complex expressions: Add comments in Code nodes
Expression Editor Tips:
  • Press Ctrl+Space for autocomplete
  • Hover over variables to see their values
  • Use the “Test with sample data” feature
  • Check the expression syntax highlighting for errors

Common Patterns

API Request with Dynamic Parameters

// URL with query parameters
{{$json.baseUrl + '?page=' + $json.page + '&limit=' + $json.limit}}

// Or using template literal
{{`${$json.baseUrl}?page=${$json.page}&limit=${$json.limit}`}}

Data Validation

// Check required fields
{{
  $json.email && 
  $json.name && 
  $json.email.includes('@')
}}

// Validate number range
{{$json.age >= 18 && $json.age <= 120}}

// Validate date
{{DateTime.fromISO($json.date).isValid}}

Error Messages

// Descriptive error message
{{
  `Failed to process item ${$itemIndex + 1}: ` +
  `Missing required field '${$json.missingField}'`
}}

Next Steps

Error Handling

Handle errors and implement retry logic

Execution Modes

Understand workflow execution contexts