Claude-code-templates n8n-expression-syntax
Validate n8n expression syntax and fix common errors. Use when writing n8n expressions, using {{}} syntax, accessing $json/$node variables, troubleshooting expression errors, or working with webhook data in workflows.
git clone https://github.com/davila7/claude-code-templates
T=$(mktemp -d) && git clone --depth=1 https://github.com/davila7/claude-code-templates "$T" && mkdir -p ~/.claude/skills && cp -r "$T/cli-tool/components/skills/workflow-automation/n8n/n8n-expression-syntax" ~/.claude/skills/davila7-claude-code-templates-n8n-expression-syntax && rm -rf "$T"
cli-tool/components/skills/workflow-automation/n8n/n8n-expression-syntax/SKILL.mdn8n Expression Syntax
Expert guide for writing correct n8n expressions in workflows.
Expression Format
All dynamic content in n8n uses double curly braces:
{{expression}}
Examples:
✅ {{$json.email}} ✅ {{$json.body.name}} ✅ {{$node["HTTP Request"].json.data}} ❌ $json.email (no braces - treated as literal text) ❌ {$json.email} (single braces - invalid)
Core Variables
$json - Current Node Output
Access data from the current node:
{{$json.fieldName}} {{$json['field with spaces']}} {{$json.nested.property}} {{$json.items[0].name}}
$node - Reference Other Nodes
Access data from any previous node:
{{$node["Node Name"].json.fieldName}} {{$node["HTTP Request"].json.data}} {{$node["Webhook"].json.body.email}}
Important:
- Node names must be in quotes
- Node names are case-sensitive
- Must match exact node name from workflow
$now - Current Timestamp
Access current date/time:
{{$now}} {{$now.toFormat('yyyy-MM-dd')}} {{$now.toFormat('HH:mm:ss')}} {{$now.plus({days: 7})}}
$env - Environment Variables
Access environment variables:
{{$env.API_KEY}} {{$env.DATABASE_URL}}
🚨 CRITICAL: Webhook Data Structure
Most Common Mistake: Webhook data is NOT at the root!
Webhook Node Output Structure
{ "headers": {...}, "params": {...}, "query": {...}, "body": { // ⚠️ USER DATA IS HERE! "name": "John", "email": "john@example.com", "message": "Hello" } }
Correct Webhook Data Access
❌ WRONG: {{$json.name}} ❌ WRONG: {{$json.email}} ✅ CORRECT: {{$json.body.name}} ✅ CORRECT: {{$json.body.email}} ✅ CORRECT: {{$json.body.message}}
Why: Webhook node wraps incoming data under
.body property to preserve headers, params, and query parameters.
Common Patterns
Access Nested Fields
// Simple nesting {{$json.user.email}} // Array access {{$json.data[0].name}} {{$json.items[0].id}} // Bracket notation for spaces {{$json['field name']}} {{$json['user data']['first name']}}
Reference Other Nodes
// Node without spaces {{$node["Set"].json.value}} // Node with spaces (common!) {{$node["HTTP Request"].json.data}} {{$node["Respond to Webhook"].json.message}} // Webhook node {{$node["Webhook"].json.body.email}}
Combine Variables
// Concatenation (automatic) Hello {{$json.body.name}}! // In URLs https://api.example.com/users/{{$json.body.user_id}} // In object properties { "name": "={{$json.body.name}}", "email": "={{$json.body.email}}" }
When NOT to Use Expressions
❌ Code Nodes
Code nodes use direct JavaScript access, NOT expressions!
// ❌ WRONG in Code node const email = '={{$json.email}}'; const name = '{{$json.body.name}}'; // ✅ CORRECT in Code node const email = $json.email; const name = $json.body.name; // Or using Code node API const email = $input.item.json.email; const allItems = $input.all();
❌ Webhook Paths
// ❌ WRONG path: "{{$json.user_id}}/webhook" // ✅ CORRECT path: "user-webhook" // Static paths only
❌ Credential Fields
// ❌ WRONG apiKey: "={{$env.API_KEY}}" // ✅ CORRECT Use n8n credential system, not expressions
Validation Rules
1. Always Use {{}}
Expressions must be wrapped in double curly braces.
❌ $json.field ✅ {{$json.field}}
2. Use Quotes for Spaces
Field or node names with spaces require bracket notation:
❌ {{$json.field name}} ✅ {{$json['field name']}} ❌ {{$node.HTTP Request.json}} ✅ {{$node["HTTP Request"].json}}
3. Match Exact Node Names
Node references are case-sensitive:
❌ {{$node["http request"].json}} // lowercase ❌ {{$node["Http Request"].json}} // wrong case ✅ {{$node["HTTP Request"].json}} // exact match
4. No Nested {{}}
Don't double-wrap expressions:
❌ {{{$json.field}}} ✅ {{$json.field}}
Common Mistakes
For complete error catalog with fixes, see COMMON_MISTAKES.md
Quick Fixes
| Mistake | Fix |
|---|---|
| |
| |
| |
| |
(webhook) | |
(Code node) | |
Working Examples
For real workflow examples, see EXAMPLES.md
Example 1: Webhook to Slack
Webhook receives:
{ "body": { "name": "John Doe", "email": "john@example.com", "message": "Hello!" } }
In Slack node text field:
New form submission! Name: {{$json.body.name}} Email: {{$json.body.email}} Message: {{$json.body.message}}
Example 2: HTTP Request to Email
HTTP Request returns:
{ "data": { "items": [ {"name": "Product 1", "price": 29.99} ] } }
In Email node (reference HTTP Request):
Product: {{$node["HTTP Request"].json.data.items[0].name}} Price: ${{$node["HTTP Request"].json.data.items[0].price}}
Example 3: Format Timestamp
// Current date {{$now.toFormat('yyyy-MM-dd')}} // Result: 2025-10-20 // Time {{$now.toFormat('HH:mm:ss')}} // Result: 14:30:45 // Full datetime {{$now.toFormat('yyyy-MM-dd HH:mm')}} // Result: 2025-10-20 14:30
Data Type Handling
Arrays
// First item {{$json.users[0].email}} // Array length {{$json.users.length}} // Last item {{$json.users[$json.users.length - 1].name}}
Objects
// Dot notation (no spaces) {{$json.user.email}} // Bracket notation (with spaces or dynamic) {{$json['user data'].email}}
Strings
// Concatenation (automatic) Hello {{$json.name}}! // String methods {{$json.email.toLowerCase()}} {{$json.name.toUpperCase()}}
Numbers
// Direct use {{$json.price}} // Math operations {{$json.price * 1.1}} // Add 10% {{$json.quantity + 5}}
Advanced Patterns
Conditional Content
// Ternary operator {{$json.status === 'active' ? 'Active User' : 'Inactive User'}} // Default values {{$json.email || 'no-email@example.com'}}
Date Manipulation
// Add days {{$now.plus({days: 7}).toFormat('yyyy-MM-dd')}} // Subtract hours {{$now.minus({hours: 24}).toISO()}} // Set specific date {{DateTime.fromISO('2025-12-25').toFormat('MMMM dd, yyyy')}}
String Manipulation
// Substring {{$json.email.substring(0, 5)}} // Replace {{$json.message.replace('old', 'new')}} // Split and join {{$json.tags.split(',').join(', ')}}
Debugging Expressions
Test in Expression Editor
- Click field with expression
- Open expression editor (click "fx" icon)
- See live preview of result
- Check for errors highlighted in red
Common Error Messages
"Cannot read property 'X' of undefined" → Parent object doesn't exist → Check your data path
"X is not a function" → Trying to call method on non-function → Check variable type
Expression shows as literal text → Missing {{ }} → Add curly braces
Expression Helpers
Available Methods
String:
,.toLowerCase().toUpperCase()
,.trim()
,.replace().substring()
,.split().includes()
Array:
,.length
,.map().filter()
,.find()
,.join().slice()
DateTime (Luxon):
,.toFormat()
,.toISO().toLocal()
,.plus()
,.minus().set()
Number:
,.toFixed().toString()- Math operations:
,+
,-
,*
,/%
Best Practices
✅ Do
- Always use {{ }} for dynamic content
- Use bracket notation for field names with spaces
- Reference webhook data from
.body - Use $node for data from other nodes
- Test expressions in expression editor
❌ Don't
- Don't use expressions in Code nodes
- Don't forget quotes around node names with spaces
- Don't double-wrap with extra {{ }}
- Don't assume webhook data is at root (it's under .body!)
- Don't use expressions in webhook paths or credentials
Related Skills
- n8n MCP Tools Expert: Learn how to validate expressions using MCP tools
- n8n Workflow Patterns: See expressions in real workflow examples
- n8n Node Configuration: Understand when expressions are needed
Summary
Essential Rules:
- Wrap expressions in {{ }}
- Webhook data is under
.body - No {{ }} in Code nodes
- Quote node names with spaces
- Node names are case-sensitive
Most Common Mistakes:
- Missing {{ }} → Add braces
in webhooks → Use{{$json.name}}{{$json.body.name}}
in Code → Use{{$json.email}}$json.email
→ Use{{$node.HTTP Request}}{{$node["HTTP Request"]}}
For more details, see:
- COMMON_MISTAKES.md - Complete error catalog
- EXAMPLES.md - Real workflow examples
Need Help? Reference the n8n expression documentation or use n8n-mcp validation tools to check your expressions.