| name | n8n-expression-syntax |
| description | 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. |
n8n 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": {
"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
{
{
$json.user.email;
}
}
{
{
$json.data[0].name;
}
}
{
{
$json.items[0].id;
}
}
{
{
$json["field name"];
}
}
{
{
$json["user data"]["first name"];
}
}
Reference Other Nodes
{
{
$node["Set"].json.value;
}
}
{
{
$node["HTTP Request"].json.data;
}
}
{
{
$node["Respond to Webhook"].json.message;
}
}
{
{
$node["Webhook"].json.body.email;
}
}
Combine Variables
Hello {{$json.body.name}}!
https:
{
"name": "={{$json.body.name}}",
"email": "={{$json.body.email}}"
}
When NOT to Use Expressions
❌ Code Nodes
Code nodes use direct JavaScript access, NOT expressions!
const email = "={{$json.email}}";
const name = "{{$json.body.name}}";
const email = $json.email;
const name = $json.body.name;
const email = $input.item.json.email;
const allItems = $input.all();
❌ Webhook Paths
path: "{{$json.user_id}}/webhook";
path: "user-webhook";
❌ Credential Fields
apiKey: "={{$env.API_KEY}}"
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}}
❌ {{$node["Http Request"].json}}
✅ {{$node["HTTP Request"].json}}
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 |
|---|
$json.field | {{$json.field}} |
{{$json.field name}} | {{$json['field name']}} |
{{$node.HTTP Request}} | {{$node["HTTP Request"]}} |
{{{$json.field}}} | {{$json.field}} |
{{$json.name}} (webhook) | {{$json.body.name}} |
'={{$json.email}}' (Code node) | $json.email |
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
{
{
$now.toFormat("yyyy-MM-dd");
}
}
{
{
$now.toFormat("HH:mm:ss");
}
}
{
{
$now.toFormat("yyyy-MM-dd HH:mm");
}
}
Data Type Handling
Arrays
{
{
$json.users[0].email;
}
}
{
{
$json.users.length;
}
}
{
{
$json.users[$json.users.length - 1].name;
}
}
Objects
{
{
$json.user.email;
}
}
{
{
$json["user data"].email;
}
}
Strings
Hello {{$json.name}}!
{{$json.email.toLowerCase()}}
{{$json.name.toUpperCase()}}
Numbers
{
{
$json.price;
}
}
{
{
$json.price * 1.1;
}
}
{
{
$json.quantity + 5;
}
}
Advanced Patterns
Conditional Content
{
{
$json.status === "active" ? "Active User" : "Inactive User";
}
}
{
{
$json.email || "no-email@example.com";
}
}
Date Manipulation
{
{
$now.plus({ days: 7 }).toFormat("yyyy-MM-dd");
}
}
{
{
$now.minus({ hours: 24 }).toISO();
}
}
{
{
DateTime.fromISO("2025-12-25").toFormat("MMMM dd, yyyy");
}
}
String Manipulation
{
{
$json.email.substring(0, 5);
}
}
{
{
$json.message.replace("old", "new");
}
}
{
{
$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
{{$json.name}} in webhooks → Use {{$json.body.name}}
{{$json.email}} in Code → Use $json.email
{{$node.HTTP Request}} → Use {{$node["HTTP Request"]}}
For more details, see:
Need Help? Reference the n8n expression documentation or use n8n-mcp validation tools to check your expressions.