n8n Code Nodes
Write production-quality JavaScript and Python code inside n8n Code nodes. JavaScript is recommended for 95% of use cases; Python is available for specific needs.
When to Use Other Skills
- Expression syntax ({{ }}) in non-code node fields → use
n8n-node-expert - Workflow design, patterns, MCP tools → use
n8n-workflow-architect - Writing code inside Code nodes → you're in the right place
When to Use Code Node vs Other Nodes
Use Code node for:
- Complex transformations requiring multiple steps
- Custom calculations or business logic
- Data aggregation across items
- Recursive operations
- API response parsing with complex structure
- Multi-step conditionals
Use simpler nodes instead:
- Simple field mapping → Set node
- Basic filtering → Filter node
- Simple if/else → IF or Switch node
- HTTP requests only → HTTP Request node
JavaScript (Primary Language)
Quick Start Template
const items = $input.all();
const processed = items.map(item => ({
json: {
...item.json,
processed: true,
timestamp: new Date().toISOString()
}
}));
return processed;
Three Critical Rules
1. Return format: always [{json: {...}}]
✅ return [{json: {result: "success"}}];
✅ return items.map(item => ({json: item.json}));
✅ return []; // empty result
❌ return {json: {result: "success"}}; // missing array wrapper
❌ return [{result: "success"}]; // missing json key
❌ return "processed"; // plain string
2. Webhook data is under .body
❌ const email = $json.email;
✅ const email = $json.body.email;
3. No expression syntax {{ }} — use JavaScript directly
❌ const value = "={{$json.field}}";
✅ const value = $json.field;
✅ const value = $input.first().json.field;
Mode Selection
Run Once for All Items (default, recommended for 95% of cases):
- Code executes once, receives all items
- Access:
$input.all(),$input.first() - Use for: aggregation, filtering, batch processing, comparing items
const allItems = $input.all();
const total = allItems.reduce((sum, item) => sum + (item.json.amount || 0), 0);
return [{json: {total, count: allItems.length, average: total / allItems.length}}];
Run Once for Each Item (specialized):
- Code executes separately per item
- Access:
$input.item - Use for: per-item API calls, independent validation
const item = $input.item;
return [{json: {...item.json, processed: true}}];
Data Access Patterns
$input.all() — Get all items (most common):
const items = $input.all();
const filtered = items.filter(item => item.json.status === 'active');
return filtered.map(item => ({json: {id: item.json.id, name: item.json.name}}));
$input.first() — Get first item:
const data = $input.first().json;
return [{json: {result: processData(data)}}];
$node — Reference other nodes:
const webhookData = $node["Webhook"].json;
const apiData = $node["HTTP Request"].json;
return [{json: {combined: {webhook: webhookData, api: apiData}}}];
Built-in Functions
$helpers.httpRequest() — HTTP calls from Code:
const response = await $helpers.httpRequest({
method: 'POST',
url: 'https://api.example.com/data',
headers: {'Authorization': 'Bearer token', 'Content-Type': 'application/json'},
body: {query: $json.body.search_term}
});
return [{json: {data: response}}];
DateTime (Luxon) — Date operations:
const now = DateTime.now();
const formatted = now.toFormat('yyyy-MM-dd');
const nextWeek = now.plus({days: 7}).toFormat('yyyy-MM-dd');
const parsed = DateTime.fromISO($json.created_at).toFormat('MMMM dd, yyyy');
return [{json: {today: formatted, nextWeek, parsed}}];
$jmespath() — JSON queries:
const data = $input.first().json;
const adults = $jmespath(data, 'users[?age >= `18`]');
const names = $jmespath(data, 'users[*].name');
return [{json: {adults, names}}];
Production Patterns
1. Data Transformation & Enrichment
const items = $input.all();
return items.map(item => {
const data = item.json;
const nameParts = (data.name || '').split(' ');
return {
json: {
first_name: nameParts[0] || '',
last_name: nameParts.slice(1).join(' ') || '',
email: data.email?.toLowerCase(),
created_at: new Date().toISOString()
}
};
});
2. Multi-Source Aggregation
const items = $input.all();
const bySource = {};
for (const item of items) {
const source = item.json.source || 'unknown';
if (!bySource[source]) bySource[source] = {count: 0, total: 0};
bySource[source].count++;
bySource[source].total += item.json.amount || 0;
}
return [{json: {summary: bySource, timestamp: new Date().toISOString()}}];
3. Regex Extraction
const text = $input.first().json.body.message;
const emailPattern = /[\w.-]+@[\w.-]+\.\w+/g;
const emails = text.match(emailPattern) || [];
const urlPattern = /https?:\/\/[^\s]+/g;
const urls = text.match(urlPattern) || [];
return [{json: {emails, urls, hasAttachments: emails.length > 0 || urls.length > 0}}];
4. Top-N Filtering & Ranking
const items = $input.all();
const topItems = items
.sort((a, b) => (b.json.score || 0) - (a.json.score || 0))
.slice(0, 10);
return topItems.map(item => ({json: item.json}));
5. Threat Indicator Scoring
Pattern for security automation — score multiple indicators and produce confidence level:
const alert = $input.first().json;
let score = 0;
const reasons = [];
// Domain reputation
if (alert.sender_domain && KNOWN_BAD_DOMAINS.includes(alert.sender_domain)) {
score += 0.4;
reasons.push('known malicious domain');
}
// Attachment analysis
if (alert.has_attachment && /\.(exe|scr|bat|cmd|ps1)$/i.test(alert.attachment_name)) {
score += 0.3;
reasons.push('dangerous attachment type');
}
// SPF/DKIM
if (alert.spf_result === 'fail') { score += 0.15; reasons.push('SPF failure'); }
if (alert.dkim_result === 'fail') { score += 0.15; reasons.push('DKIM failure'); }
const confidence = score > 0.8 ? 'high' : score > 0.4 ? 'medium' : 'low';
return [{json: {score, confidence, reasons, alert_id: alert.id}}];
6. PDF/Report Data Parsing
Pattern for extracting structured data from API responses or parsed documents:
const rawData = $input.first().json;
// Extract metrics from parsed report sections
const metrics = {
emails_blocked: parseInt(rawData.summary?.match(/(\d+)\s+emails?\s+blocked/i)?.[1] || '0'),
phishing_detected: parseInt(rawData.summary?.match(/(\d+)\s+phishing/i)?.[1] || '0'),
users_trained: parseInt(rawData.training?.match(/(\d+)\s+completed/i)?.[1] || '0'),
compliance_score: parseFloat(rawData.compliance?.match(/([\d.]+)%/)?.[1] || '0')
};
return [{json: {metrics, report_date: DateTime.now().toFormat('yyyy-MM'), raw_sections: Object.keys(rawData)}}];
7. Quebec Tax Calculation
const expense = $input.first().json;
const amount = parseFloat(expense.amount);
const TPS_RATE = 0.05; // Federal GST
const TVQ_RATE = 0.09975; // Quebec QST
let taxBreakdown;
if (expense.province === 'QC' && expense.category === 'restaurant') {
// Quebec restaurant: separate TPS and TVQ
const subtotal = amount / (1 + TPS_RATE + TVQ_RATE);
taxBreakdown = {
subtotal: subtotal.toFixed(2),
tps: (subtotal * TPS_RATE).toFixed(2),
tvq: (subtotal * TVQ_RATE).toFixed(2),
total: amount.toFixed(2),
tax_type: 'QC_TPS_TVQ'
};
} else if (expense.is_foreign_saas) {
taxBreakdown = {
subtotal: amount.toFixed(2),
tps: '0.00',
tvq: '0.00',
total: amount.toFixed(2),
tax_type: 'FOREIGN_NO_ITC',
note: 'Foreign SaaS - no input tax credit'
};
} else {
// Standard GST/HST
const rate = expense.province === 'QC' ? TPS_RATE + TVQ_RATE : 0.13; // HST for ON etc.
const subtotal = amount / (1 + rate);
taxBreakdown = {
subtotal: subtotal.toFixed(2),
tax: (amount - subtotal).toFixed(2),
total: amount.toFixed(2),
tax_type: expense.province === 'QC' ? 'QC_COMBINED' : 'HST'
};
}
return [{json: {...expense, ...taxBreakdown}}];
Error Prevention
Always validate input:
const items = $input.all();
if (!items || items.length === 0) return [];
if (!items[0].json) return [{json: {error: 'Invalid input format'}}];
Use try-catch for external calls:
try {
const response = await $helpers.httpRequest({url: 'https://api.example.com/data'});
return [{json: {success: true, data: response}}];
} catch (error) {
return [{json: {success: false, error: error.message}}];
}
Use optional chaining:
❌ const email = item.json.user.email; // crashes if user is undefined
✅ const email = item.json?.user?.email || ''; // safe
Debug with console.log:
console.log(`Processing ${items.length} items`);
console.log('First item:', JSON.stringify(items[0].json, null, 2));
For complete pattern library, see references/js-patterns.md For complete error guide, see references/js-errors.md For built-in function reference, see references/js-builtins.md
Python (Secondary — Use When Needed)
Python in n8n Code nodes is in beta. Use JavaScript unless you specifically need Python standard library features or are significantly more comfortable with Python.
Key Differences from JavaScript
| Feature | JavaScript | Python |
|---|---|---|
| Data access | $input.all() | _input.all() |
| Current item | $input.item | _input.item |
| Node reference | $node["Name"].json | _node["Name"].json |
| HTTP requests | $helpers.httpRequest() | Not available — use urllib |
| DateTime | DateTime (Luxon) | datetime (standard library) |
| Return format | [{json: {...}}] | [{"json": {...}}] |
Quick Start
items = _input.all()
processed = []
for item in items:
processed.append({
"json": {
**item["json"],
"processed": True,
"timestamp": datetime.now().isoformat()
}
})
return processed
Python Limitations in n8n
- No external packages (no pip install) — standard library only
- No
$helpers.httpRequest()— useurllib.requestinstead - No Luxon DateTime — use Python's
datetime - Less community support and documentation
- Performance may vary
When Python Makes Sense
- Complex text processing (Python's regex and string handling)
- Statistical calculations (using
statisticsmodule) - Data parsing with
json,csv,xmlstandard modules - When you have existing Python logic to port
For complete Python guide, see references/python-guide.md
Deployment Checklist
- Code is not empty, has meaningful logic
- Return statement exists on all code paths
- Return format:
[{json: {...}}] - No
{{ }}expression syntax (use JS/Python directly) - Webhook data accessed via
.body - Null/undefined guards (optional chaining or explicit checks)
- Error handling (try-catch for external calls)
- Mode selected ("All Items" for most cases)
- Tested with real data
Reference Files
- references/js-patterns.md — 10 production-tested JavaScript patterns
- references/js-errors.md — Top errors and solutions
- references/js-builtins.md — $helpers, DateTime, $jmespath reference
- references/js-data-access.md — Comprehensive data access patterns
- references/python-guide.md — Python Code node complete guide