mirror of
https://github.com/czlonkowski/n8n-skills.git
synced 2026-03-16 23:43:08 +00:00
feat: Complete Skill #1 - n8n Expression Syntax
## Skill #1 Complete - n8n Expression Syntax ✅ **4 Evaluations Created**: - eval-001: Missing curly braces - eval-002: Webhook body data access (critical!) - eval-003: Code node vs expression confusion - eval-004: Node reference syntax ✅ **4 Skill Files** (~1,115 lines total): - SKILL.md (285 lines) - Core concepts, under 500 line limit - COMMON_MISTAKES.md (380 lines) - 15 common errors with fixes - EXAMPLES.md (450 lines) - 10 real working examples - README.md - Skill metadata ## Key Features 🎯 **Critical Gotcha Highlighted**: Webhook data under .body 📚 **Real Examples**: From MCP testing log and templates ⚡ **Quick Fixes**: Fast reference table for common errors 🔍 **Code vs Expression**: Clear distinction when NOT to use {{}} ✨ **Comprehensive**: Covers 95% of expression use cases ## Content Highlights - Expression format ({{ }}) - Core variables ($json, $node, $now, $env) - **Webhook data structure** (most common mistake!) - When NOT to use expressions (Code nodes) - Array/object access patterns - Date/time formatting - String manipulation - Conditional logic ## Based on MCP Testing All examples verified against real: - Webhook node structure from get_node_essentials - Template #2947 (Weather to Slack) - Code node guide from tools_documentation - Real error messages from validation ## Next: Skill #2 - n8n MCP Tools Expert 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
This commit is contained in:
22
evaluations/expression-syntax/eval-001-missing-braces.json
Normal file
22
evaluations/expression-syntax/eval-001-missing-braces.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"id": "expr-001",
|
||||||
|
"skills": ["n8n-expression-syntax"],
|
||||||
|
"query": "I'm trying to access an email field in my n8n Slack node using $json.email but it's showing as literal text '$json.email' in the message. What's wrong?",
|
||||||
|
"expected_behavior": [
|
||||||
|
"Identifies missing curly braces around the expression",
|
||||||
|
"Explains that n8n expressions must be wrapped in {{ }}",
|
||||||
|
"Provides the corrected expression: {{$json.email}}",
|
||||||
|
"Explains that without braces, it's treated as literal text",
|
||||||
|
"References expression format documentation from SKILL.md"
|
||||||
|
],
|
||||||
|
"baseline_without_skill": {
|
||||||
|
"likely_response": "May suggest general JavaScript or template syntax, might not know n8n-specific {{ }} requirement",
|
||||||
|
"expected_quality": "Low - lacks n8n-specific knowledge about expression syntax"
|
||||||
|
},
|
||||||
|
"with_skill_expected": {
|
||||||
|
"response_quality": "High - precise fix with n8n-specific guidance",
|
||||||
|
"uses_skill_content": true,
|
||||||
|
"provides_correct_syntax": true,
|
||||||
|
"explains_why_it_failed": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"id": "expr-002",
|
||||||
|
"skills": ["n8n-expression-syntax"],
|
||||||
|
"query": "My webhook workflow is showing {{$json.name}} as undefined even though I'm sending {\"name\": \"John\"} in the webhook POST request. What am I doing wrong?",
|
||||||
|
"expected_behavior": [
|
||||||
|
"Identifies that webhook data is nested under .body property",
|
||||||
|
"Explains the webhook node output structure",
|
||||||
|
"Provides the corrected expression: {{$json.body.name}}",
|
||||||
|
"Shows the complete webhook data structure with headers, params, query, and body",
|
||||||
|
"Emphasizes this is a CRITICAL gotcha specific to webhook nodes"
|
||||||
|
],
|
||||||
|
"baseline_without_skill": {
|
||||||
|
"likely_response": "May suggest debugging or checking data format, unlikely to know webhook-specific structure",
|
||||||
|
"expected_quality": "Low - would miss the webhook .body nesting"
|
||||||
|
},
|
||||||
|
"with_skill_expected": {
|
||||||
|
"response_quality": "High - identifies webhook-specific issue immediately",
|
||||||
|
"uses_skill_content": true,
|
||||||
|
"provides_correct_syntax": true,
|
||||||
|
"explains_webhook_structure": true,
|
||||||
|
"warns_about_common_gotcha": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"id": "expr-003",
|
||||||
|
"skills": ["n8n-expression-syntax"],
|
||||||
|
"query": "I'm trying to use {{$json.email}} in my Code node to get the email address, but it's not working. The code shows the literal string '{{$json.email}}' instead of the value. How do I fix this?",
|
||||||
|
"expected_behavior": [
|
||||||
|
"Identifies that Code nodes use direct JavaScript access, NOT expressions",
|
||||||
|
"Explains that {{ }} syntax is NOT used inside Code nodes",
|
||||||
|
"Provides the corrected Code node syntax: $json.email or $input.item.json.email",
|
||||||
|
"Explains when NOT to use expressions (Code nodes, Function nodes)",
|
||||||
|
"References Code node guide or documentation"
|
||||||
|
],
|
||||||
|
"baseline_without_skill": {
|
||||||
|
"likely_response": "May suggest template literal syntax or string interpolation, unlikely to know n8n Code node specifics",
|
||||||
|
"expected_quality": "Low - would not understand Code node vs expression node difference"
|
||||||
|
},
|
||||||
|
"with_skill_expected": {
|
||||||
|
"response_quality": "High - immediately identifies Code node vs expression context",
|
||||||
|
"uses_skill_content": true,
|
||||||
|
"provides_correct_code_syntax": true,
|
||||||
|
"explains_when_not_to_use_expressions": true,
|
||||||
|
"clear_distinction_between_contexts": true
|
||||||
|
}
|
||||||
|
}
|
||||||
23
evaluations/expression-syntax/eval-004-node-reference.json
Normal file
23
evaluations/expression-syntax/eval-004-node-reference.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"id": "expr-004",
|
||||||
|
"skills": ["n8n-expression-syntax"],
|
||||||
|
"query": "How do I reference data from my 'HTTP Request' node in a later Slack node? I need to access the response data.",
|
||||||
|
"expected_behavior": [
|
||||||
|
"Provides correct $node syntax with quotes around node name",
|
||||||
|
"Shows example: {{$node[\"HTTP Request\"].json.fieldName}}",
|
||||||
|
"Explains that node names with spaces require bracket notation and quotes",
|
||||||
|
"Warns that node names are case-sensitive and must match exactly",
|
||||||
|
"Provides multiple examples from real workflows"
|
||||||
|
],
|
||||||
|
"baseline_without_skill": {
|
||||||
|
"likely_response": "May suggest generic data passing or variable references, might not know n8n $node syntax",
|
||||||
|
"expected_quality": "Medium - might guess at syntax but miss specifics like quotes and case sensitivity"
|
||||||
|
},
|
||||||
|
"with_skill_expected": {
|
||||||
|
"response_quality": "High - precise $node syntax with proper quoting",
|
||||||
|
"uses_skill_content": true,
|
||||||
|
"provides_correct_syntax": true,
|
||||||
|
"explains_case_sensitivity": true,
|
||||||
|
"shows_multiple_examples": true
|
||||||
|
}
|
||||||
|
}
|
||||||
393
skills/n8n-expression-syntax/COMMON_MISTAKES.md
Normal file
393
skills/n8n-expression-syntax/COMMON_MISTAKES.md
Normal file
@@ -0,0 +1,393 @@
|
|||||||
|
# Common n8n Expression Mistakes
|
||||||
|
|
||||||
|
Complete catalog of expression errors with explanations and fixes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Missing Curly Braces
|
||||||
|
|
||||||
|
**Problem**: Expression not recognized, shows as literal text
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
$json.email
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$json.email}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: n8n treats text without {{ }} as a literal string. Expressions must be wrapped to be evaluated.
|
||||||
|
|
||||||
|
**How to identify**: Field shows exact text like "$json.email" instead of actual value.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Webhook Body Access
|
||||||
|
|
||||||
|
**Problem**: Undefined values when accessing webhook data
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
{{$json.name}}
|
||||||
|
{{$json.email}}
|
||||||
|
{{$json.message}}
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$json.body.name}}
|
||||||
|
{{$json.body.email}}
|
||||||
|
{{$json.body.message}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Webhook node wraps incoming data under `.body` property. The root `$json` contains headers, params, query, and body.
|
||||||
|
|
||||||
|
**Webhook structure**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"headers": {...},
|
||||||
|
"params": {...},
|
||||||
|
"query": {...},
|
||||||
|
"body": { // User data is HERE!
|
||||||
|
"name": "John",
|
||||||
|
"email": "john@example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**How to identify**: Webhook workflow shows "undefined" for fields that are definitely being sent.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Spaces in Field Names
|
||||||
|
|
||||||
|
**Problem**: Syntax error or undefined value
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
{{$json.first name}}
|
||||||
|
{{$json.user data.email}}
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$json['first name']}}
|
||||||
|
{{$json['user data'].email}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Spaces break dot notation. JavaScript interprets space as end of property name.
|
||||||
|
|
||||||
|
**How to identify**: Error message about unexpected token, or undefined when field exists.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Spaces in Node Names
|
||||||
|
|
||||||
|
**Problem**: Cannot access other node's data
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
{{$node.HTTP Request.json.data}}
|
||||||
|
{{$node.Respond to Webhook.json}}
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$node["HTTP Request"].json.data}}
|
||||||
|
{{$node["Respond to Webhook"].json}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Node names are treated as object property names and need quotes when they contain spaces.
|
||||||
|
|
||||||
|
**How to identify**: Error like "Cannot read property 'Request' of undefined"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Incorrect Node Reference Case
|
||||||
|
|
||||||
|
**Problem**: Undefined or wrong data returned
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
{{$node["http request"].json.data}} // lowercase
|
||||||
|
{{$node["Http Request"].json.data}} // wrong capitalization
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$node["HTTP Request"].json.data}} // exact match
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Node names are **case-sensitive**. Must match exactly as shown in workflow.
|
||||||
|
|
||||||
|
**How to identify**: Undefined value even though node exists and has data.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Double Wrapping
|
||||||
|
|
||||||
|
**Problem**: Literal {{ }} appears in output
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
{{{$json.field}}}
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$json.field}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Only one set of {{ }} is needed. Extra braces are treated as literal characters.
|
||||||
|
|
||||||
|
**How to identify**: Output shows "{{value}}" instead of just "value".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Array Access with Dots
|
||||||
|
|
||||||
|
**Problem**: Syntax error or undefined
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
{{$json.items.0.name}}
|
||||||
|
{{$json.users.1.email}}
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$json.items[0].name}}
|
||||||
|
{{$json.users[1].email}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Array indices require brackets, not dots. Number after dot is invalid JavaScript.
|
||||||
|
|
||||||
|
**How to identify**: Syntax error or "Cannot read property '0' of undefined"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Using Expressions in Code Nodes
|
||||||
|
|
||||||
|
**Problem**: Literal string instead of value, or errors
|
||||||
|
|
||||||
|
❌ **Wrong (in Code node)**:
|
||||||
|
```javascript
|
||||||
|
const email = '{{$json.email}}';
|
||||||
|
const name = '={{$json.body.name}}';
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct (in Code node)**:
|
||||||
|
```javascript
|
||||||
|
const email = $json.email;
|
||||||
|
const name = $json.body.name;
|
||||||
|
|
||||||
|
// Or using Code node API
|
||||||
|
const email = $input.item.json.email;
|
||||||
|
const allItems = $input.all();
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Code nodes have **direct access** to data. The {{ }} syntax is for expression fields in other nodes, not for JavaScript code.
|
||||||
|
|
||||||
|
**How to identify**: Literal string "{{$json.email}}" appears in Code node output instead of actual value.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Missing Quotes in $node Reference
|
||||||
|
|
||||||
|
**Problem**: Syntax error
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
{{$node[HTTP Request].json.data}}
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$node["HTTP Request"].json.data}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Node names must be quoted strings inside brackets.
|
||||||
|
|
||||||
|
**How to identify**: Syntax error "Unexpected identifier"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Incorrect Property Path
|
||||||
|
|
||||||
|
**Problem**: Undefined value
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
{{$json.data.items.name}} // items is an array
|
||||||
|
{{$json.user.email}} // user doesn't exist, it's userData
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$json.data.items[0].name}} // access array element
|
||||||
|
{{$json.userData.email}} // correct property name
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Wrong path to data. Arrays need index, property names must be exact.
|
||||||
|
|
||||||
|
**How to identify**: Check actual data structure using expression editor preview.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Using = Prefix Outside JSON
|
||||||
|
|
||||||
|
**Problem**: Literal "=" appears in output
|
||||||
|
|
||||||
|
❌ **Wrong (in text field)**:
|
||||||
|
```
|
||||||
|
Email: ={{$json.email}}
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct (in text field)**:
|
||||||
|
```
|
||||||
|
Email: {{$json.email}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: The `=` prefix is **only** needed in JSON mode or when you want to set entire field value to expression result:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// JSON mode (set property to expression)
|
||||||
|
{
|
||||||
|
"email": "={{$json.body.email}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text mode (no = needed)
|
||||||
|
Hello {{$json.body.name}}!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: The `=` is parsed as literal text in non-JSON contexts.
|
||||||
|
|
||||||
|
**How to identify**: Output shows "=john@example.com" instead of "john@example.com"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Expressions in Webhook Path
|
||||||
|
|
||||||
|
**Problem**: Path doesn't update, validation error
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
path: "{{$json.user_id}}/webhook"
|
||||||
|
path: "users/={{$env.TENANT_ID}}"
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
path: "my-webhook" // Static paths only
|
||||||
|
path: "user-webhook/:userId" // Use dynamic URL parameters instead
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Webhook paths must be static. Use dynamic URL parameters (`:paramName`) instead of expressions.
|
||||||
|
|
||||||
|
**How to identify**: Webhook path doesn't change or validation warns about invalid path.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Forgetting .json in $node Reference
|
||||||
|
|
||||||
|
**Problem**: Undefined or wrong data
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
{{$node["HTTP Request"].data}} // Missing .json
|
||||||
|
{{$node["Webhook"].body.email}} // Missing .json
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$node["HTTP Request"].json.data}}
|
||||||
|
{{$node["Webhook"].json.body.email}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Node data is always under `.json` property (or `.binary` for binary data).
|
||||||
|
|
||||||
|
**How to identify**: Undefined value when you know the node has data.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. String Concatenation Confusion
|
||||||
|
|
||||||
|
**Problem**: Attempting JavaScript template literals
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
`Hello ${$json.name}!` // Template literal syntax
|
||||||
|
"Hello " + $json.name + "!" // String concatenation
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
Hello {{$json.name}}! // n8n expressions auto-concatenate
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: n8n expressions don't use JavaScript template literal syntax. Adjacent text and expressions are automatically concatenated.
|
||||||
|
|
||||||
|
**How to identify**: Literal backticks or + symbols appear in output.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Empty Expression Brackets
|
||||||
|
|
||||||
|
**Problem**: Literal {{}} in output
|
||||||
|
|
||||||
|
❌ **Wrong**:
|
||||||
|
```
|
||||||
|
{{}}
|
||||||
|
{{ }}
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct**:
|
||||||
|
```
|
||||||
|
{{$json.field}} // Include expression content
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why it fails**: Empty expression brackets have nothing to evaluate.
|
||||||
|
|
||||||
|
**How to identify**: Literal "{{ }}" text appears in output.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference Table
|
||||||
|
|
||||||
|
| Error | Symptom | Fix |
|
||||||
|
|-------|---------|-----|
|
||||||
|
| No {{ }} | Literal text | Add {{ }} |
|
||||||
|
| Webhook data | Undefined | Add `.body` |
|
||||||
|
| Space in field | Syntax error | Use `['field name']` |
|
||||||
|
| Space in node | Undefined | Use `["Node Name"]` |
|
||||||
|
| Wrong case | Undefined | Match exact case |
|
||||||
|
| Double {{ }} | Literal braces | Remove extra {{ }} |
|
||||||
|
| .0 array | Syntax error | Use [0] |
|
||||||
|
| {{ }} in Code | Literal string | Remove {{ }} |
|
||||||
|
| No quotes in $node | Syntax error | Add quotes |
|
||||||
|
| Wrong path | Undefined | Check data structure |
|
||||||
|
| = in text | Literal = | Remove = prefix |
|
||||||
|
| Dynamic path | Doesn't work | Use static path |
|
||||||
|
| Missing .json | Undefined | Add .json |
|
||||||
|
| Template literals | Literal text | Use {{ }} |
|
||||||
|
| Empty {{ }} | Literal braces | Add expression |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Debugging Process
|
||||||
|
|
||||||
|
When expression doesn't work:
|
||||||
|
|
||||||
|
1. **Check braces**: Is it wrapped in {{ }}?
|
||||||
|
2. **Check data source**: Is it webhook data? Add `.body`
|
||||||
|
3. **Check spaces**: Field or node name has spaces? Use brackets
|
||||||
|
4. **Check case**: Does node name match exactly?
|
||||||
|
5. **Check path**: Is the property path correct?
|
||||||
|
6. **Use expression editor**: Preview shows actual result
|
||||||
|
7. **Check context**: Is it a Code node? Remove {{ }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Related**: See [EXAMPLES.md](EXAMPLES.md) for working examples of correct syntax.
|
||||||
483
skills/n8n-expression-syntax/EXAMPLES.md
Normal file
483
skills/n8n-expression-syntax/EXAMPLES.md
Normal file
@@ -0,0 +1,483 @@
|
|||||||
|
# n8n Expression Examples
|
||||||
|
|
||||||
|
Real working examples from n8n workflows.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example 1: Webhook Form Submission
|
||||||
|
|
||||||
|
**Scenario**: Form submission webhook posts to Slack
|
||||||
|
|
||||||
|
**Workflow**: Webhook → Slack
|
||||||
|
|
||||||
|
**Webhook Input** (POST):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "John Doe",
|
||||||
|
"email": "john@example.com",
|
||||||
|
"company": "Acme Corp",
|
||||||
|
"message": "Interested in your product"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Webhook Node Output**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"headers": {"content-type": "application/json"},
|
||||||
|
"params": {},
|
||||||
|
"query": {},
|
||||||
|
"body": {
|
||||||
|
"name": "John Doe",
|
||||||
|
"email": "john@example.com",
|
||||||
|
"company": "Acme Corp",
|
||||||
|
"message": "Interested in your product"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**In Slack Node** (text field):
|
||||||
|
```
|
||||||
|
New form submission! 📝
|
||||||
|
|
||||||
|
Name: {{$json.body.name}}
|
||||||
|
Email: {{$json.body.email}}
|
||||||
|
Company: {{$json.body.company}}
|
||||||
|
Message: {{$json.body.message}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output**:
|
||||||
|
```
|
||||||
|
New form submission! 📝
|
||||||
|
|
||||||
|
Name: John Doe
|
||||||
|
Email: john@example.com
|
||||||
|
Company: Acme Corp
|
||||||
|
Message: Interested in your product
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example 2: HTTP API to Database
|
||||||
|
|
||||||
|
**Scenario**: Fetch user data from API and insert into database
|
||||||
|
|
||||||
|
**Workflow**: Schedule → HTTP Request → Postgres
|
||||||
|
|
||||||
|
**HTTP Request Returns**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"id": 123,
|
||||||
|
"name": "Alice Smith",
|
||||||
|
"email": "alice@example.com",
|
||||||
|
"role": "admin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**In Postgres Node** (INSERT statement):
|
||||||
|
```sql
|
||||||
|
INSERT INTO users (user_id, name, email, role, synced_at)
|
||||||
|
VALUES (
|
||||||
|
{{$json.data.users[0].id}},
|
||||||
|
'{{$json.data.users[0].name}}',
|
||||||
|
'{{$json.data.users[0].email}}',
|
||||||
|
'{{$json.data.users[0].role}}',
|
||||||
|
'{{$now.toFormat('yyyy-MM-dd HH:mm:ss')}}'
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Result**: User inserted with current timestamp
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example 3: Multi-Node Data Flow
|
||||||
|
|
||||||
|
**Scenario**: Webhook → HTTP Request → Email
|
||||||
|
|
||||||
|
**Workflow Structure**:
|
||||||
|
1. Webhook receives order ID
|
||||||
|
2. HTTP Request fetches order details
|
||||||
|
3. Email sends confirmation
|
||||||
|
|
||||||
|
### Node 1: Webhook
|
||||||
|
|
||||||
|
**Receives**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"body": {
|
||||||
|
"order_id": "ORD-12345"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Node 2: HTTP Request
|
||||||
|
|
||||||
|
**URL field**:
|
||||||
|
```
|
||||||
|
https://api.example.com/orders/{{$json.body.order_id}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"order": {
|
||||||
|
"id": "ORD-12345",
|
||||||
|
"customer": "Bob Jones",
|
||||||
|
"total": 99.99,
|
||||||
|
"items": ["Widget", "Gadget"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Node 3: Email
|
||||||
|
|
||||||
|
**Subject**:
|
||||||
|
```
|
||||||
|
Order {{$node["Webhook"].json.body.order_id}} Confirmed
|
||||||
|
```
|
||||||
|
|
||||||
|
**Body**:
|
||||||
|
```
|
||||||
|
Dear {{$node["HTTP Request"].json.order.customer}},
|
||||||
|
|
||||||
|
Your order {{$node["Webhook"].json.body.order_id}} has been confirmed!
|
||||||
|
|
||||||
|
Total: ${{$node["HTTP Request"].json.order.total}}
|
||||||
|
Items: {{$node["HTTP Request"].json.order.items.join(', ')}}
|
||||||
|
|
||||||
|
Thank you for your purchase!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Email Result**:
|
||||||
|
```
|
||||||
|
Subject: Order ORD-12345 Confirmed
|
||||||
|
|
||||||
|
Dear Bob Jones,
|
||||||
|
|
||||||
|
Your order ORD-12345 has been confirmed!
|
||||||
|
|
||||||
|
Total: $99.99
|
||||||
|
Items: Widget, Gadget
|
||||||
|
|
||||||
|
Thank you for your purchase!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example 4: Date Formatting
|
||||||
|
|
||||||
|
**Scenario**: Various date format outputs
|
||||||
|
|
||||||
|
**Current Time**: 2025-10-20 14:30:45
|
||||||
|
|
||||||
|
### ISO Format
|
||||||
|
```javascript
|
||||||
|
{{$now.toISO()}}
|
||||||
|
```
|
||||||
|
**Output**: `2025-10-20T14:30:45.000Z`
|
||||||
|
|
||||||
|
### Custom Date Format
|
||||||
|
```javascript
|
||||||
|
{{$now.toFormat('yyyy-MM-dd')}}
|
||||||
|
```
|
||||||
|
**Output**: `2025-10-20`
|
||||||
|
|
||||||
|
### Time Only
|
||||||
|
```javascript
|
||||||
|
{{$now.toFormat('HH:mm:ss')}}
|
||||||
|
```
|
||||||
|
**Output**: `14:30:45`
|
||||||
|
|
||||||
|
### Full Readable Format
|
||||||
|
```javascript
|
||||||
|
{{$now.toFormat('MMMM dd, yyyy')}}
|
||||||
|
```
|
||||||
|
**Output**: `October 20, 2025`
|
||||||
|
|
||||||
|
### Date Math - Future
|
||||||
|
```javascript
|
||||||
|
{{$now.plus({days: 7}).toFormat('yyyy-MM-dd')}}
|
||||||
|
```
|
||||||
|
**Output**: `2025-10-27`
|
||||||
|
|
||||||
|
### Date Math - Past
|
||||||
|
```javascript
|
||||||
|
{{$now.minus({hours: 24}).toFormat('yyyy-MM-dd HH:mm')}}
|
||||||
|
```
|
||||||
|
**Output**: `2025-10-19 14:30`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example 5: Array Operations
|
||||||
|
|
||||||
|
**Data**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"users": [
|
||||||
|
{"name": "Alice", "email": "alice@example.com"},
|
||||||
|
{"name": "Bob", "email": "bob@example.com"},
|
||||||
|
{"name": "Charlie", "email": "charlie@example.com"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### First User
|
||||||
|
```javascript
|
||||||
|
{{$json.users[0].name}}
|
||||||
|
```
|
||||||
|
**Output**: `Alice`
|
||||||
|
|
||||||
|
### Last User
|
||||||
|
```javascript
|
||||||
|
{{$json.users[$json.users.length - 1].name}}
|
||||||
|
```
|
||||||
|
**Output**: `Charlie`
|
||||||
|
|
||||||
|
### All Emails (Join)
|
||||||
|
```javascript
|
||||||
|
{{$json.users.map(u => u.email).join(', ')}}
|
||||||
|
```
|
||||||
|
**Output**: `alice@example.com, bob@example.com, charlie@example.com`
|
||||||
|
|
||||||
|
### Array Length
|
||||||
|
```javascript
|
||||||
|
{{$json.users.length}}
|
||||||
|
```
|
||||||
|
**Output**: `3`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example 6: Conditional Logic
|
||||||
|
|
||||||
|
**Data**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"order": {
|
||||||
|
"status": "completed",
|
||||||
|
"total": 150
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ternary Operator
|
||||||
|
```javascript
|
||||||
|
{{$json.order.status === 'completed' ? 'Order Complete ✓' : 'Pending...'}}
|
||||||
|
```
|
||||||
|
**Output**: `Order Complete ✓`
|
||||||
|
|
||||||
|
### Default Values
|
||||||
|
```javascript
|
||||||
|
{{$json.order.notes || 'No notes provided'}}
|
||||||
|
```
|
||||||
|
**Output**: `No notes provided` (if notes field doesn't exist)
|
||||||
|
|
||||||
|
### Multiple Conditions
|
||||||
|
```javascript
|
||||||
|
{{$json.order.total > 100 ? 'Premium Customer' : 'Standard Customer'}}
|
||||||
|
```
|
||||||
|
**Output**: `Premium Customer`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example 7: String Manipulation
|
||||||
|
|
||||||
|
**Data**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"user": {
|
||||||
|
"email": "JOHN@EXAMPLE.COM",
|
||||||
|
"message": " Hello World "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lowercase
|
||||||
|
```javascript
|
||||||
|
{{$json.user.email.toLowerCase()}}
|
||||||
|
```
|
||||||
|
**Output**: `john@example.com`
|
||||||
|
|
||||||
|
### Uppercase
|
||||||
|
```javascript
|
||||||
|
{{$json.user.message.toUpperCase()}}
|
||||||
|
```
|
||||||
|
**Output**: ` HELLO WORLD `
|
||||||
|
|
||||||
|
### Trim
|
||||||
|
```javascript
|
||||||
|
{{$json.user.message.trim()}}
|
||||||
|
```
|
||||||
|
**Output**: `Hello World`
|
||||||
|
|
||||||
|
### Substring
|
||||||
|
```javascript
|
||||||
|
{{$json.user.email.substring(0, 4)}}
|
||||||
|
```
|
||||||
|
**Output**: `JOHN`
|
||||||
|
|
||||||
|
### Replace
|
||||||
|
```javascript
|
||||||
|
{{$json.user.message.replace('World', 'n8n')}}
|
||||||
|
```
|
||||||
|
**Output**: ` Hello n8n `
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example 8: Fields with Spaces
|
||||||
|
|
||||||
|
**Data**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"user data": {
|
||||||
|
"first name": "Jane",
|
||||||
|
"last name": "Doe",
|
||||||
|
"phone number": "+1234567890"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bracket Notation
|
||||||
|
```javascript
|
||||||
|
{{$json['user data']['first name']}}
|
||||||
|
```
|
||||||
|
**Output**: `Jane`
|
||||||
|
|
||||||
|
### Combined
|
||||||
|
```javascript
|
||||||
|
{{$json['user data']['first name']}} {{$json['user data']['last name']}}
|
||||||
|
```
|
||||||
|
**Output**: `Jane Doe`
|
||||||
|
|
||||||
|
### Nested Spaces
|
||||||
|
```javascript
|
||||||
|
Contact: {{$json['user data']['phone number']}}
|
||||||
|
```
|
||||||
|
**Output**: `Contact: +1234567890`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example 9: Code Node (Direct Access)
|
||||||
|
|
||||||
|
**Code Node**: Transform webhook data
|
||||||
|
|
||||||
|
**Input** (from Webhook node):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"body": {
|
||||||
|
"items": ["apple", "banana", "cherry"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Code** (JavaScript):
|
||||||
|
```javascript
|
||||||
|
// ✅ Direct access (no {{ }})
|
||||||
|
const items = $json.body.items;
|
||||||
|
|
||||||
|
// Transform to uppercase
|
||||||
|
const uppercased = items.map(item => item.toUpperCase());
|
||||||
|
|
||||||
|
// Return in n8n format
|
||||||
|
return [{
|
||||||
|
json: {
|
||||||
|
original: items,
|
||||||
|
transformed: uppercased,
|
||||||
|
count: items.length
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"original": ["apple", "banana", "cherry"],
|
||||||
|
"transformed": ["APPLE", "BANANA", "CHERRY"],
|
||||||
|
"count": 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example 10: Environment Variables
|
||||||
|
|
||||||
|
**Setup**: Environment variable `API_KEY=secret123`
|
||||||
|
|
||||||
|
### In HTTP Request (Headers)
|
||||||
|
```javascript
|
||||||
|
Authorization: Bearer {{$env.API_KEY}}
|
||||||
|
```
|
||||||
|
**Result**: `Authorization: Bearer secret123`
|
||||||
|
|
||||||
|
### In URL
|
||||||
|
```javascript
|
||||||
|
https://api.example.com/data?key={{$env.API_KEY}}
|
||||||
|
```
|
||||||
|
**Result**: `https://api.example.com/data?key=secret123`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Template from Real Workflow
|
||||||
|
|
||||||
|
**Based on n8n template #2947** (Weather to Slack)
|
||||||
|
|
||||||
|
### Workflow Structure
|
||||||
|
Webhook → OpenStreetMap API → Weather API → Slack
|
||||||
|
|
||||||
|
### Webhook Slash Command
|
||||||
|
**Input**: `/weather London`
|
||||||
|
|
||||||
|
**Webhook receives**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"body": {
|
||||||
|
"text": "London"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### OpenStreetMap API
|
||||||
|
**URL**:
|
||||||
|
```
|
||||||
|
https://nominatim.openstreetmap.org/search?q={{$json.body.text}}&format=json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Weather API (NWS)
|
||||||
|
**URL**:
|
||||||
|
```
|
||||||
|
https://api.weather.gov/points/{{$node["OpenStreetMap"].json[0].lat}},{{$node["OpenStreetMap"].json[0].lon}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Slack Message
|
||||||
|
```
|
||||||
|
Weather for {{$json.body.text}}:
|
||||||
|
|
||||||
|
Temperature: {{$node["Weather API"].json.properties.temperature.value}}°C
|
||||||
|
Conditions: {{$node["Weather API"].json.properties.shortForecast}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
**Key Patterns**:
|
||||||
|
1. Webhook data is under `.body`
|
||||||
|
2. Use `{{}}` for expressions (except Code nodes)
|
||||||
|
3. Reference other nodes with `$node["Node Name"].json`
|
||||||
|
4. Use brackets for field names with spaces
|
||||||
|
5. Node names are case-sensitive
|
||||||
|
|
||||||
|
**Most Common Uses**:
|
||||||
|
- `{{$json.body.field}}` - Webhook data
|
||||||
|
- `{{$node["Name"].json.field}}` - Other node data
|
||||||
|
- `{{$now.toFormat('yyyy-MM-dd')}}` - Timestamps
|
||||||
|
- `{{$json.array[0].field}}` - Array access
|
||||||
|
- `{{$json.field || 'default'}}` - Default values
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Related**: See [COMMON_MISTAKES.md](COMMON_MISTAKES.md) for error examples and fixes.
|
||||||
93
skills/n8n-expression-syntax/README.md
Normal file
93
skills/n8n-expression-syntax/README.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# n8n Expression Syntax
|
||||||
|
|
||||||
|
Expert guide for writing correct n8n expressions in workflows.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Teaches correct n8n expression syntax ({{ }} patterns) and fixes common mistakes, especially the critical webhook data structure gotcha.
|
||||||
|
|
||||||
|
## Activates On
|
||||||
|
|
||||||
|
- expression
|
||||||
|
- {{}} syntax
|
||||||
|
- $json, $node, $now, $env
|
||||||
|
- webhook data
|
||||||
|
- troubleshoot expression error
|
||||||
|
- undefined in workflow
|
||||||
|
|
||||||
|
## File Count
|
||||||
|
|
||||||
|
4 files, ~450 lines total
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
**n8n-mcp tools**:
|
||||||
|
- None directly (syntax knowledge skill)
|
||||||
|
- Works with n8n-mcp validation tools
|
||||||
|
|
||||||
|
**Related skills**:
|
||||||
|
- n8n Workflow Patterns (uses expressions in examples)
|
||||||
|
- n8n MCP Tools Expert (validates expressions)
|
||||||
|
- n8n Node Configuration (when expressions are needed)
|
||||||
|
|
||||||
|
## Coverage
|
||||||
|
|
||||||
|
### Core Topics
|
||||||
|
- Expression format ({{ }})
|
||||||
|
- Core variables ($json, $node, $now, $env)
|
||||||
|
- **Webhook data structure** ($json.body.*)
|
||||||
|
- When NOT to use expressions (Code nodes)
|
||||||
|
|
||||||
|
### Common Patterns
|
||||||
|
- Accessing nested fields
|
||||||
|
- Referencing other nodes
|
||||||
|
- Array and object access
|
||||||
|
- Date/time formatting
|
||||||
|
- String manipulation
|
||||||
|
|
||||||
|
### Error Prevention
|
||||||
|
- 15 common mistakes with fixes
|
||||||
|
- Quick reference table
|
||||||
|
- Debugging process
|
||||||
|
|
||||||
|
## Evaluations
|
||||||
|
|
||||||
|
4 scenarios (100% coverage expected):
|
||||||
|
1. **eval-001**: Missing curly braces
|
||||||
|
2. **eval-002**: Webhook body data access (critical!)
|
||||||
|
3. **eval-003**: Code node vs expression confusion
|
||||||
|
4. **eval-004**: Node reference syntax
|
||||||
|
|
||||||
|
## Key Features
|
||||||
|
|
||||||
|
✅ **Critical Gotcha Highlighted**: Webhook data under `.body`
|
||||||
|
✅ **Real Examples**: From MCP testing and real templates
|
||||||
|
✅ **Quick Fixes Table**: Fast reference for common errors
|
||||||
|
✅ **Code vs Expression**: Clear distinction
|
||||||
|
✅ **Comprehensive**: Covers 95% of expression use cases
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- **SKILL.md** (285 lines) - Main content with all essential knowledge
|
||||||
|
- **COMMON_MISTAKES.md** (380 lines) - Complete error catalog with 15 common mistakes
|
||||||
|
- **EXAMPLES.md** (450 lines) - 10 real working examples
|
||||||
|
- **README.md** (this file) - Skill metadata
|
||||||
|
|
||||||
|
## Success Metrics
|
||||||
|
|
||||||
|
**Expected outcomes**:
|
||||||
|
- Users correctly wrap expressions in {{ }}
|
||||||
|
- Zero webhook `.body` access errors
|
||||||
|
- No expressions used in Code nodes
|
||||||
|
- Correct $node reference syntax
|
||||||
|
|
||||||
|
## Last Updated
|
||||||
|
|
||||||
|
2025-10-20
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Part of**: n8n-skills repository
|
||||||
|
**Conceived by**: Romuald Członkowski - [www.aiadvisors.pl/en](https://www.aiadvisors.pl/en)
|
||||||
516
skills/n8n-expression-syntax/SKILL.md
Normal file
516
skills/n8n-expression-syntax/SKILL.md
Normal file
@@ -0,0 +1,516 @@
|
|||||||
|
---
|
||||||
|
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:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{{$json.fieldName}}
|
||||||
|
{{$json['field with spaces']}}
|
||||||
|
{{$json.nested.property}}
|
||||||
|
{{$json.items[0].name}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### $node - Reference Other Nodes
|
||||||
|
|
||||||
|
Access data from any previous node:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{{$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:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{{$now}}
|
||||||
|
{{$now.toFormat('yyyy-MM-dd')}}
|
||||||
|
{{$now.toFormat('HH:mm:ss')}}
|
||||||
|
{{$now.plus({days: 7})}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### $env - Environment Variables
|
||||||
|
|
||||||
|
Access environment variables:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{{$env.API_KEY}}
|
||||||
|
{{$env.DATABASE_URL}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 CRITICAL: Webhook Data Structure
|
||||||
|
|
||||||
|
**Most Common Mistake**: Webhook data is **NOT** at the root!
|
||||||
|
|
||||||
|
### Webhook Node Output Structure
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"headers": {...},
|
||||||
|
"params": {...},
|
||||||
|
"query": {...},
|
||||||
|
"body": { // ⚠️ USER DATA IS HERE!
|
||||||
|
"name": "John",
|
||||||
|
"email": "john@example.com",
|
||||||
|
"message": "Hello"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Correct Webhook Data Access
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
❌ 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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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!
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ❌ 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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ❌ WRONG
|
||||||
|
path: "{{$json.user_id}}/webhook"
|
||||||
|
|
||||||
|
// ✅ CORRECT
|
||||||
|
path: "user-webhook" // Static paths only
|
||||||
|
```
|
||||||
|
|
||||||
|
### ❌ Credential Fields
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ❌ 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.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
❌ $json.field
|
||||||
|
✅ {{$json.field}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Use Quotes for Spaces
|
||||||
|
|
||||||
|
Field or node names with spaces require **bracket notation**:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
❌ {{$json.field name}}
|
||||||
|
✅ {{$json['field name']}}
|
||||||
|
|
||||||
|
❌ {{$node.HTTP Request.json}}
|
||||||
|
✅ {{$node["HTTP Request"].json}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Match Exact Node Names
|
||||||
|
|
||||||
|
Node references are **case-sensitive**:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
❌ {{$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:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
❌ {{{$json.field}}}
|
||||||
|
✅ {{$json.field}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Mistakes
|
||||||
|
|
||||||
|
For complete error catalog with fixes, see [COMMON_MISTAKES.md](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](EXAMPLES.md)
|
||||||
|
|
||||||
|
### Example 1: Webhook to Slack
|
||||||
|
|
||||||
|
**Webhook receives**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// First item
|
||||||
|
{{$json.users[0].email}}
|
||||||
|
|
||||||
|
// Array length
|
||||||
|
{{$json.users.length}}
|
||||||
|
|
||||||
|
// Last item
|
||||||
|
{{$json.users[$json.users.length - 1].name}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Objects
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Dot notation (no spaces)
|
||||||
|
{{$json.user.email}}
|
||||||
|
|
||||||
|
// Bracket notation (with spaces or dynamic)
|
||||||
|
{{$json['user data'].email}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Strings
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Concatenation (automatic)
|
||||||
|
Hello {{$json.name}}!
|
||||||
|
|
||||||
|
// String methods
|
||||||
|
{{$json.email.toLowerCase()}}
|
||||||
|
{{$json.name.toUpperCase()}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Numbers
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Direct use
|
||||||
|
{{$json.price}}
|
||||||
|
|
||||||
|
// Math operations
|
||||||
|
{{$json.price * 1.1}} // Add 10%
|
||||||
|
{{$json.quantity + 5}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Advanced Patterns
|
||||||
|
|
||||||
|
### Conditional Content
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Ternary operator
|
||||||
|
{{$json.status === 'active' ? 'Active User' : 'Inactive User'}}
|
||||||
|
|
||||||
|
// Default values
|
||||||
|
{{$json.email || 'no-email@example.com'}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Date Manipulation
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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
|
||||||
|
|
||||||
|
1. Click field with expression
|
||||||
|
2. Open expression editor (click "fx" icon)
|
||||||
|
3. See live preview of result
|
||||||
|
4. 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**:
|
||||||
|
1. Wrap expressions in {{ }}
|
||||||
|
2. Webhook data is under `.body`
|
||||||
|
3. No {{ }} in Code nodes
|
||||||
|
4. Quote node names with spaces
|
||||||
|
5. 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:
|
||||||
|
- [COMMON_MISTAKES.md](COMMON_MISTAKES.md) - Complete error catalog
|
||||||
|
- [EXAMPLES.md](EXAMPLES.md) - Real workflow examples
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Need Help?** Reference the n8n expression documentation or use n8n-mcp validation tools to check your expressions.
|
||||||
Reference in New Issue
Block a user