# n8n Expression Reference

This guide provides comprehensive reference for writing n8n expressions.

## Table of Contents
- [Basic Syntax](#basic-syntax)
- [Accessing Data](#accessing-data)
- [String Operations](#string-operations)
- [Number Operations](#number-operations)
- [Date & Time](#date--time)
- [Array Operations](#array-operations)
- [Object Operations](#object-operations)
- [Conditional Logic](#conditional-logic)
- [JSON Operations](#json-operations)
- [Common Patterns](#common-patterns)

## Basic Syntax

n8n expressions are wrapped in double curly braces:
```
{{ expression }}
```

You can combine text with expressions:
```
Hello {{ $json.name }}, your order #{{ $json.orderId }} is ready!
```

## Accessing Data

### Current Item Data
```javascript
// Access field in current item
{{ $json.fieldName }}

// Nested fields
{{ $json.user.email }}
{{ $json.data.items[0].name }}

// Access by bracket notation
{{ $json["field-with-dashes"] }}
```

### Previous Node Data
```javascript
// Access data from a specific node
{{ $node["HTTP Request"].json.data }}

// Access by node index
{{ $("HTTP Request").item.json.result }}

// First item from previous node
{{ $node["HTTP Request"].json }}

// Specific item by index
{{ $items("HTTP Request")[0].json.field }}
```

### Input Data
```javascript
// Current input item
{{ $input.item.json.field }}

// All input items
{{ $input.all() }}

// First input item
{{ $input.first().json.field }}

// Last input item
{{ $input.last().json.field }}
```

### Binary Data
```javascript
// Access binary data
{{ $binary.data }}

// Binary data from specific node
{{ $node["Read File"].binary.data }}
```

### Workflow & Execution Data
```javascript
// Workflow ID
{{ $workflow.id }}

// Workflow name
{{ $workflow.name }}

// Execution ID
{{ $execution.id }}

// Execution mode (manual, trigger, webhook)
{{ $execution.mode }}

// Current timestamp
{{ $now }}

// Today's date at midnight
{{ $today }}
```

## String Operations

### Basic Methods
```javascript
// Convert to lowercase
{{ $json.email.toLowerCase() }}

// Convert to uppercase
{{ $json.name.toUpperCase() }}

// Trim whitespace
{{ $json.text.trim() }}

// Get length
{{ $json.message.length }}
```

### Splitting & Joining
```javascript
// Split string into array
{{ $json.email.split('@') }}

// Get specific part after split
{{ $json.email.split('@')[1] }}

// Join array into string
{{ $json.tags.join(', ') }}
```

### Search & Replace
```javascript
// Replace first occurrence
{{ $json.text.replace('old', 'new') }}

// Replace all occurrences
{{ $json.text.replaceAll('old', 'new') }}

// Check if string includes substring
{{ $json.text.includes('keyword') }}

// Check if string starts with
{{ $json.url.startsWith('https://') }}

// Check if string ends with
{{ $json.filename.endsWith('.pdf') }}

// Find position of substring
{{ $json.text.indexOf('word') }}
```

### Substring & Slicing
```javascript
// Get substring (start, length)
{{ $json.text.substring(0, 10) }}

// Slice string (start, end)
{{ $json.text.slice(0, 5) }}

// Get first character
{{ $json.name[0] }}

// Get last character
{{ $json.name[$json.name.length - 1] }}
```

### Advanced String Operations
```javascript
// Pad start with zeros
{{ $json.id.toString().padStart(5, '0') }}

// Pad end with spaces
{{ $json.text.padEnd(20, ' ') }}

// Repeat string
{{ '-'.repeat(10) }}

// Match regex
{{ $json.text.match(/\d+/) }}

// Test regex
{{ /^\d{5}$/.test($json.zipCode) }}
```

## Number Operations

### Basic Math
```javascript
// Addition
{{ $json.price + 10 }}

// Subtraction
{{ $json.total - $json.discount }}

// Multiplication
{{ $json.quantity * $json.price }}

// Division
{{ $json.total / $json.items }}

// Modulo (remainder)
{{ $json.number % 2 }}

// Exponentiation
{{ $json.base ** $json.exponent }}
```

### Parsing & Formatting
```javascript
// Parse string to integer
{{ parseInt($json.value) }}

// Parse string to float
{{ parseFloat($json.price) }}

// Round to 2 decimal places
{{ parseFloat($json.amount).toFixed(2) }}

// Round to nearest integer
{{ Math.round($json.value) }}

// Round up
{{ Math.ceil($json.value) }}

// Round down
{{ Math.floor($json.value) }}
```

### Math Functions
```javascript
// Absolute value
{{ Math.abs($json.difference) }}

// Maximum value
{{ Math.max($json.value1, $json.value2, $json.value3) }}

// Minimum value
{{ Math.min($json.value1, $json.value2, $json.value3) }}

// Random number (0-1)
{{ Math.random() }}

// Random integer (0-99)
{{ Math.floor(Math.random() * 100) }}

// Square root
{{ Math.sqrt($json.number) }}

// Power
{{ Math.pow($json.base, $json.exponent) }}
```

### Number Validation
```javascript
// Check if number
{{ !isNaN($json.value) }}

// Check if integer
{{ Number.isInteger($json.value) }}

// Check if finite
{{ isFinite($json.value) }}
```

## Date & Time

### Current Date & Time
```javascript
// Current timestamp (ISO format)
{{ $now }}

// Today at midnight
{{ $today }}

// Using DateTime (Luxon)
{{ DateTime.now().toISO() }}

// Current timestamp in milliseconds
{{ Date.now() }}
```

### Creating Dates
```javascript
// From ISO string
{{ DateTime.fromISO($json.dateString) }}

// From format
{{ DateTime.fromFormat($json.date, 'yyyy-MM-dd') }}

// From timestamp
{{ DateTime.fromMillis($json.timestamp) }}

// Specific date
{{ DateTime.fromObject({ year: 2024, month: 1, day: 15 }) }}
```

### Formatting Dates
```javascript
// ISO format
{{ DateTime.now().toISO() }}

// Custom format
{{ DateTime.now().toFormat('yyyy-MM-dd') }}
{{ DateTime.now().toFormat('dd.MM.yyyy HH:mm:ss') }}
{{ DateTime.now().toFormat('MMMM dd, yyyy') }}

// Locale-specific
{{ DateTime.now().toLocaleString(DateTime.DATE_FULL) }}
{{ DateTime.now().toLocaleString(DateTime.DATETIME_MED) }}

// Relative time
{{ DateTime.now().toRelative() }}
```

### Date Arithmetic
```javascript
// Add time
{{ DateTime.now().plus({ days: 7 }) }}
{{ DateTime.now().plus({ hours: 2, minutes: 30 }) }}
{{ DateTime.now().plus({ months: 1 }) }}

// Subtract time
{{ DateTime.now().minus({ days: 30 }) }}
{{ DateTime.now().minus({ years: 1 }) }}

// Difference between dates
{{ DateTime.now().diff(DateTime.fromISO($json.startDate), 'days').days }}
{{ DateTime.now().diff(DateTime.fromISO($json.startDate), ['years', 'months', 'days']) }}
```

### Date Components
```javascript
// Get year
{{ DateTime.now().year }}

// Get month (1-12)
{{ DateTime.now().month }}

// Get day
{{ DateTime.now().day }}

// Get hour
{{ DateTime.now().hour }}

// Get minute
{{ DateTime.now().minute }}

// Get day of week (1-7, Mon-Sun)
{{ DateTime.now().weekday }}

// Get day name
{{ DateTime.now().weekdayLong }}

// Get month name
{{ DateTime.now().monthLong }}
```

### Date Manipulation
```javascript
// Start of day
{{ DateTime.now().startOf('day') }}

// End of month
{{ DateTime.now().endOf('month') }}

// Start of week
{{ DateTime.now().startOf('week') }}

// Set specific time
{{ DateTime.now().set({ hour: 9, minute: 0, second: 0 }) }}
```

## Array Operations

### Basic Array Methods
```javascript
// Get array length
{{ $json.items.length }}

// Access element by index
{{ $json.items[0] }}

// Last element
{{ $json.items[$json.items.length - 1] }}

// Join array
{{ $json.tags.join(', ') }}

// Check if array includes value
{{ $json.items.includes('value') }}
```

### Transforming Arrays
```javascript
// Map: transform each element
{{ $json.users.map(user => user.email) }}
{{ $json.prices.map(p => parseFloat(p) * 1.2) }}

// Filter: keep elements matching condition
{{ $json.users.filter(user => user.active === true) }}
{{ $json.numbers.filter(n => n > 10) }}

// Find: get first matching element
{{ $json.users.find(user => user.id === 123) }}

// Find index
{{ $json.items.findIndex(item => item.name === 'Product') }}

// Some: check if any element matches
{{ $json.items.some(item => item.price > 100) }}

// Every: check if all elements match
{{ $json.items.every(item => item.inStock === true) }}
```

### Array Aggregation
```javascript
// Reduce: calculate sum
{{ $json.prices.reduce((sum, price) => sum + parseFloat(price), 0) }}

// Calculate average
{{ $json.numbers.reduce((sum, n) => sum + n, 0) / $json.numbers.length }}

// Find maximum
{{ Math.max(...$json.numbers) }}

// Find minimum
{{ Math.min(...$json.numbers) }}

// Count occurrences
{{ $json.items.filter(item => item.status === 'active').length }}
```

### Sorting Arrays
```javascript
// Sort numbers ascending
{{ $json.numbers.sort((a, b) => a - b) }}

// Sort numbers descending
{{ $json.numbers.sort((a, b) => b - a) }}

// Sort strings alphabetically
{{ $json.names.sort() }}

// Sort objects by property
{{ $json.users.sort((a, b) => a.name.localeCompare(b.name)) }}
```

### Array Manipulation
```javascript
// Slice: get portion of array
{{ $json.items.slice(0, 5) }}

// Concat: combine arrays
{{ $json.array1.concat($json.array2) }}

// Flat: flatten nested arrays
{{ $json.nestedArray.flat() }}

// Unique values (using Set)
{{ [...new Set($json.items)] }}

// Reverse array
{{ $json.items.reverse() }}
```

## Object Operations

### Accessing Properties
```javascript
// Dot notation
{{ $json.user.name }}

// Bracket notation
{{ $json["property-name"] }}

// Nested access
{{ $json.data.user.addresses[0].city }}
```

### Object Methods
```javascript
// Get all keys
{{ Object.keys($json) }}

// Get all values
{{ Object.values($json) }}

// Get entries (key-value pairs)
{{ Object.entries($json) }}

// Check if property exists
{{ $json.hasOwnProperty('email') }}

// Check if object has any properties
{{ Object.keys($json).length > 0 }}
```

### Object Transformation
```javascript
// Merge objects
{{ Object.assign({}, $json.obj1, $json.obj2) }}

// Spread operator
{{ {...$json.user, role: 'admin'} }}

// Extract specific properties
{{ (({ name, email }) => ({ name, email }))($json.user) }}

// Map object to array
{{ Object.entries($json).map(([key, value]) => ({ key, value })) }}
```

## Conditional Logic

### Ternary Operator
```javascript
// Basic ternary
{{ $json.status === 'active' ? 'Active' : 'Inactive' }}

// Nested ternary
{{ $json.score >= 90 ? 'A' : $json.score >= 80 ? 'B' : 'C' }}

// With numbers
{{ $json.quantity > 0 ? $json.price * $json.quantity : 0 }}
```

### If Function
```javascript
// Basic if
{{ $if($json.premium === true, 'Premium User', 'Regular User') }}

// With expressions
{{ $if($json.total > 100, $json.total * 0.9, $json.total) }}
```

### Logical Operators
```javascript
// AND
{{ $json.age >= 18 && $json.verified === true }}

// OR
{{ $json.role === 'admin' || $json.role === 'moderator' }}

// NOT
{{ !$json.deleted }}

// Nullish coalescing
{{ $json.name ?? 'Unknown' }}

// Default value
{{ $json.value || 'default' }}
```

### Comparison
```javascript
// Equality
{{ $json.status === 'completed' }}

// Inequality
{{ $json.type !== 'test' }}

// Greater than
{{ $json.score > 50 }}

// Less than or equal
{{ $json.price <= 99.99 }}

// Type checking
{{ typeof $json.value === 'string' }}
```

## JSON Operations

### Parsing & Stringifying
```javascript
// Parse JSON string
{{ JSON.parse($json.jsonString) }}

// Stringify object
{{ JSON.stringify($json.data) }}

// Stringify with formatting
{{ JSON.stringify($json.data, null, 2) }}
```

### Handling JSON Errors
```javascript
// Safe JSON parse with try/catch in Code node
try {
  const data = JSON.parse(items[0].json.rawData);
  return [{json: data}];
} catch (error) {
  return [{json: {error: 'Invalid JSON', raw: items[0].json.rawData}}];
}
```

## Common Patterns

### Email Validation
```javascript
// Check if valid email format
{{ /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test($json.email) }}

// Extract domain from email
{{ $json.email.split('@')[1] }}

// Normalize email
{{ $json.email.toLowerCase().trim() }}
```

### URL Operations
```javascript
// Extract domain from URL
{{ new URL($json.url).hostname }}

// Get URL parameters
{{ new URL($json.url).searchParams.get('id') }}

// Build URL with parameters
{{ `https://api.example.com/users?id=${$json.userId}&format=json` }}
```

### Phone Number Formatting
```javascript
// Remove non-digits
{{ $json.phone.replace(/\D/g, '') }}

// Format US phone
{{ $json.phone.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3') }}
```

### Price/Currency Formatting
```javascript
// Format as currency
{{ parseFloat($json.price).toFixed(2) }}

// Add currency symbol
{{ `$${parseFloat($json.price).toFixed(2)}` }}

// Calculate with tax
{{ (parseFloat($json.price) * 1.19).toFixed(2) }}
```

### Name Formatting
```javascript
// Capitalize first letter
{{ $json.name.charAt(0).toUpperCase() + $json.name.slice(1).toLowerCase() }}

// Title case
{{ $json.name.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ') }}

// Initials
{{ $json.firstName[0] + $json.lastName[0] }}
```

### Generating IDs
```javascript
// Random UUID-like string
{{ Math.random().toString(36).substring(2, 15) }}

// Timestamp-based ID
{{ Date.now().toString(36) }}

// Sequential ID with padding
{{ String($json.index).padStart(6, '0') }}
```

### Data Validation
```javascript
// Check if empty
{{ !$json.value || $json.value.trim() === '' }}

// Check if valid number
{{ !isNaN(parseFloat($json.value)) }}

// Check if array has items
{{ Array.isArray($json.items) && $json.items.length > 0 }}

// Check if date is in future
{{ DateTime.fromISO($json.date) > DateTime.now() }}
```

### Data Cleaning
```javascript
// Remove duplicates from array
{{ [...new Set($json.items)] }}

// Remove null/undefined values
{{ $json.items.filter(item => item != null) }}

// Remove empty strings
{{ $json.values.filter(v => v !== '') }}

// Trim all strings in array
{{ $json.items.map(item => item.trim()) }}
```

## Best Practices

1. **Use meaningful variable names in Code nodes**
2. **Test expressions with sample data** before deploying
3. **Handle null/undefined values** with nullish coalescing (`??`)
4. **Use Set node for simple transformations**, Code node for complex logic
5. **Break complex expressions** into multiple steps for readability
6. **Check data structure** in debug panel before writing expressions
7. **Use DateTime for dates**, not JavaScript Date (better timezone support)
8. **Validate data** before processing to avoid runtime errors
9. **Document complex expressions** with comments in Code nodes
10. **Cache frequently used values** in variables to avoid repetition

## Additional Resources

- Official n8n Expression docs: https://docs.n8n.io/code-examples/expressions/
- Luxon DateTime docs: https://moment.github.io/luxon/
- JavaScript reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript
