n8n Expression SyntaxCAUTION
n8n skillset for Claude Code to build flawless n8n workflows
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
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
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)
$jmespath(object, query)— querying nested JSON in one expression, with the quoting rules that fail silently- Runtime errors inside
{{ }}resolve tonull(node still succeeds) — how to surface them
Common Patterns
- Accessing nested fields
- Referencing other nodes
- Array and object access
- Date/time formatting
- String manipulation
Error Prevention
- 17 common mistakes with fixes (incl. JMESPath quoting and the silent-null runtime error)
- Quick reference table
- Debugging process
Evaluations
6 scenarios (100% coverage expected):
- eval-001: Missing curly braces
- eval-002: Webhook body data access (critical!)
- eval-003: Code node vs expression confusion
- eval-004: Node reference syntax
- eval-005:
$jmespathquoting (double-quoted string, bare number) - eval-006: Filter drops everything on a green run (silent null)
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
e25b729cc88aOBSERVED · 2026-10-26What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
---
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, 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. Also use when asked whether a complex expression hurts performance.
---
# 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}}
```
**Warning**: Some n8n instances have `N8N_BLOCK_ENV_ACCESS_IN_NODE` enabled, which blocks `$env` access entirely. If `$env` returns errors, use alternative approaches:
- Store values in credentials instead
- Use a Set node with manually entered values
- Pass values through webhook query parameters
---
## 🚨 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": "[email protected]",
"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
```
---
## The transform gatekeeper
Before you add a node — or write any code — to transform data, walk this order and stop at the first that fits:
1. **The service's own node** does it in its own fields: a CRM node's field slots, the Slack node's Blocks field, a
Data Table insert's per-column slots. HTTP Request only when no node covers the operation.
2. **A native node for the job.** Filter, IF / Switch, Summarize, Aggregate, Split Out, Merge, Compare Datasets, Remove
Duplicates, Sort + Limit, Date & Time, XML / HTML / Extract From File, HTTP Request pagination, Crypto. The job-to-node
table in `using-n8n-mcp-skills` maps jobs to nodes; their configs are in `n8n-node-configuration` → NATIVE_NODES.md.
3. **A short expression** (`{{ ... }}`) inside that node's field. Property access, method chains
(`.map().filter().join()`), a ternary, string building, Luxon date math, the helper functions below — "take A,
produce B" in one expression, without intermediate variables.
- **Querying nested JSON for one field** (pick, filter, sum inside an array) → `$jmespath()` in that same expression
(rules below). When downstream needs one item per element, use Split Out / Filter / Aggregate instead.
4. **Code node**, only for the closed list: loops or recursion no node expresses, state across runs, parsing no node
handles, an allowlisted library, heavy all-items work (thousands of items, stated or measured), or one short Code node
(~15 lines) replacing 4+ glue nodes. Give it a `Why Code:` note. See `n8n-code-javascript`.
**A function body is code.** When the logic needs `const`, `if`, `return` or several statements — an
`(() => { ... })()` wrapped in `{{ }}` — it has outgrown an expression. Split itTrust audit
CAUTIONgrade B · trust 89/100 Install with care. The audit found things worth knowing before you trust its output.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | NA |
| L2 | Instruction surface (what it tells the agent) | FAIL |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (1)
Access environment variables:
Gates applied: no_behavioural_pass.
e25b729cc88afull audit observations/trust-audit/skill/czlonkowski__n8n-expression-syntax.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-26 | e25b729cc88a | CAUTION | B | 89 | first audit |
Questions
What does the n8n-expression-syntax — czlonkowski/n8n-skills skill do?
n8n skillset for Claude Code to build flawless n8n workflows
Is n8n-expression-syntax — czlonkowski/n8n-skills safe to install?
With care. The audit graded it B (89/100) and found 1 thing worth knowing before you trust this skill, listed below with the exact line each was found on.
What can n8n-expression-syntax — czlonkowski/n8n-skills access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
How current is this page?
The grade is for one exact copy of the source (e25b729cc88a), read on 2026-10-26. The repository is watched, and a new audit runs when it changes — this is the first audit.
Add this badge to your README
Shows this page's audit result and links back to it. It updates when the audit does.
[](https://modelsatlas.com/skills/czlonkowski/n8n-expression-syntax/)
Not your listing, or something out of date? Claim or update your listing.