skills/n8n-expression-syntax/SKILL.md
Validate n8n expression syntax and fix common errors. Use when writing n8n expressions, using {{}} syntax, accessing $json/$node variables, troubleshooting expression errors, mapping data between nodes, or referencing webhook data in workflows. Use this skill whenever configuring node fields that reference data from previous nodes — expressions are how n8n passes data between nodes, and getting the syntax wrong is the most common source of workflow errors.
npx skillsauth add czlonkowski/n8n-skills n8n-expression-syntaxInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert guide for writing correct n8n expressions in workflows.
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)
Access data from the current node:
{{$json.fieldName}}
{{$json['field with spaces']}}
{{$json.nested.property}}
{{$json.items[0].name}}
Access data from any previous node:
{{$node["Node Name"].json.fieldName}}
{{$node["HTTP Request"].json.data}}
{{$node["Webhook"].json.body.email}}
Important:
Access current date/time:
{{$now}}
{{$now.toFormat('yyyy-MM-dd')}}
{{$now.toFormat('HH:mm:ss')}}
{{$now.plus({days: 7})}}
Access environment variables:
{{$env.API_KEY}}
{{$env.DATABASE_URL}}
Warning: Some n8n instances have N8N_BLOCK_ENV_ACCESS_IN_NODE enabled, which blocks $env access entirely. If $env returns errors, use alternative approaches:
Most Common Mistake: Webhook data is NOT at the root!
{
"headers": {...},
"params": {...},
"query": {...},
"body": { // ⚠️ USER DATA IS HERE!
"name": "John",
"email": "[email protected]",
"message": "Hello"
}
}
❌ 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.
// 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']}}
// 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}}
// 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}}"
}
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();
// ❌ WRONG
path: "{{$json.user_id}}/webhook"
// ✅ CORRECT
path: "user-webhook" // Static paths only
// ❌ WRONG
apiKey: "={{$env.API_KEY}}"
// ✅ CORRECT
Use n8n credential system, not expressions
Expressions must be wrapped in double curly braces.
❌ $json.field
✅ {{$json.field}}
Field or node names with spaces, diacritics, or special characters require bracket notation:
❌ {{$json.field name}}
✅ {{$json['field name']}}
❌ {{$node.HTTP Request.json}}
✅ {{$node["HTTP Request"].json}}
// Bracket notation is mandatory for keys with special characters
✅ {{$json['Gross Price w/o shipment']}}
✅ {{$json['Cena brutto zł']}}
Node references are case-sensitive:
❌ {{$node["http request"].json}} // lowercase
❌ {{$node["Http Request"].json}} // wrong case
✅ {{$node["HTTP Request"].json}} // exact match
Don't double-wrap expressions:
❌ {{{$json.field}}}
✅ {{$json.field}}
For complete error catalog with fixes, see COMMON_MISTAKES.md
| 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 |
For real workflow examples, see EXAMPLES.md
Webhook receives:
{
"body": {
"name": "John Doe",
"email": "[email protected]",
"message": "Hello!"
}
}
In Slack node text field:
New form submission!
Name: {{$json.body.name}}
Email: {{$json.body.email}}
Message: {{$json.body.message}}
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}}
// 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
// First item
{{$json.users[0].email}}
// Array length
{{$json.users.length}}
// Last item
{{$json.users[$json.users.length - 1].name}}
// Dot notation (no spaces)
{{$json.user.email}}
// Bracket notation (with spaces or dynamic)
{{$json['user data'].email}}
// Concatenation (automatic)
Hello {{$json.name}}!
// String methods
{{$json.email.toLowerCase()}}
{{$json.name.toUpperCase()}}
// Direct use
{{$json.price}}
// Math operations
{{$json.price * 1.1}} // Add 10%
{{$json.quantity + 5}}
// Ternary operator
{{$json.status === 'active' ? 'Active User' : 'Inactive User'}}
// Default values
{{$json.email || '[email protected]'}}
// 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')}}
// Substring
{{$json.email.substring(0, 5)}}
// Replace
{{$json.message.replace('old', 'new')}}
// Split and join
{{$json.tags.split(',').join(', ')}}
"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
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()+, -, *, /, %.bodyEssential Rules:
.bodyMost Common Mistakes:
{{$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.
tools
Expert guide for using n8n-mcp MCP tools effectively. Use when searching for nodes, validating configurations, accessing templates, managing workflows, managing credentials, auditing instance security, or using any n8n-mcp tool. Provides tool selection guidance, parameter formats, and common patterns. IMPORTANT — Always consult this skill before calling any n8n-mcp tool — it prevents common mistakes like wrong nodeType formats, incorrect parameter structures, and inefficient tool usage. If the user mentions n8n, workflows, nodes, or automation and you have n8n MCP tools available, use this skill first.
tools
Write JavaScript code in n8n Code nodes. Use when writing JavaScript in n8n, using $input/$json/$node syntax, making HTTP requests with $helpers, working with dates using DateTime, troubleshooting Code node errors, choosing between Code node modes, or doing any custom data transformation in n8n. Always use this skill when a workflow needs a Code node — whether for data aggregation, filtering, API calls, format conversion, batch processing logic, or any custom JavaScript. Covers SplitInBatches loop patterns, cross-iteration data, pairedItem, and real-world production patterns.
tools
Proven workflow architectural patterns from real n8n workflows. Use when building new workflows, designing workflow structure, choosing workflow patterns, planning workflow architecture, or asking about webhook processing, HTTP API integration, database operations, AI agent workflows, batch processing, or scheduled tasks. Always consult this skill when the user asks to create, build, or design an n8n workflow, automate a process, or connect services — even if they don't explicitly mention 'patterns'. Covers webhook, API, database, AI, batch processing, and scheduled automation architectures.
testing
Interpret validation errors and guide fixing them. Use when encountering validation errors, validation warnings, false positives, operator structure issues, or need help understanding validation results. Also use when asking about validation profiles, error types, the validation loop process, or auto-fix capabilities. Consult this skill whenever a validate_node or validate_workflow call returns errors or warnings — it knows which warnings are false positives and which errors need real fixes.