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, or choosing between Code node modes.
Add this skill
npx mdskills install czlonkowski/n8n-code-javascriptComprehensive guide with production patterns, error prevention, and excellent coverage of common pitfalls
1---2name: n8n-code-javascript3description: 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, or choosing between Code node modes.4---56# JavaScript Code Node78Expert guidance for writing JavaScript code in n8n Code nodes.910---1112## Quick Start1314```javascript15// Basic template for Code nodes16const items = $input.all();1718// Process data19const processed = items.map(item => ({20 json: {21 ...item.json,22 processed: true,23 timestamp: new Date().toISOString()24 }25}));2627return processed;28```2930### Essential Rules31321. **Choose "Run Once for All Items" mode** (recommended for most use cases)332. **Access data**: `$input.all()`, `$input.first()`, or `$input.item`343. **CRITICAL**: Must return `[{json: {...}}]` format354. **CRITICAL**: Webhook data is under `$json.body` (not `$json` directly)365. **Built-ins available**: $helpers.httpRequest(), DateTime (Luxon), $jmespath()3738---3940## Mode Selection Guide4142The Code node offers two execution modes. Choose based on your use case:4344### Run Once for All Items (Recommended - Default)4546**Use this mode for:** 95% of use cases4748- **How it works**: Code executes **once** regardless of input count49- **Data access**: `$input.all()` or `items` array50- **Best for**: Aggregation, filtering, batch processing, transformations, API calls with all data51- **Performance**: Faster for multiple items (single execution)5253```javascript54// Example: Calculate total from all items55const allItems = $input.all();56const total = allItems.reduce((sum, item) => sum + (item.json.amount || 0), 0);5758return [{59 json: {60 total,61 count: allItems.length,62 average: total / allItems.length63 }64}];65```6667**When to use:**68- ✅ Comparing items across the dataset69- ✅ Calculating totals, averages, or statistics70- ✅ Sorting or ranking items71- ✅ Deduplication72- ✅ Building aggregated reports73- ✅ Combining data from multiple items7475### Run Once for Each Item7677**Use this mode for:** Specialized cases only7879- **How it works**: Code executes **separately** for each input item80- **Data access**: `$input.item` or `$item`81- **Best for**: Item-specific logic, independent operations, per-item validation82- **Performance**: Slower for large datasets (multiple executions)8384```javascript85// Example: Add processing timestamp to each item86const item = $input.item;8788return [{89 json: {90 ...item.json,91 processed: true,92 processedAt: new Date().toISOString()93 }94}];95```9697**When to use:**98- ✅ Each item needs independent API call99- ✅ Per-item validation with different error handling100- ✅ Item-specific transformations based on item properties101- ✅ When items must be processed separately for business logic102103**Decision Shortcut:**104- **Need to look at multiple items?** → Use "All Items" mode105- **Each item completely independent?** → Use "Each Item" mode106- **Not sure?** → Use "All Items" mode (you can always loop inside)107108---109110## Data Access Patterns111112### Pattern 1: $input.all() - Most Common113114**Use when**: Processing arrays, batch operations, aggregations115116```javascript117// Get all items from previous node118const allItems = $input.all();119120// Filter, map, reduce as needed121const valid = allItems.filter(item => item.json.status === 'active');122const mapped = valid.map(item => ({123 json: {124 id: item.json.id,125 name: item.json.name126 }127}));128129return mapped;130```131132### Pattern 2: $input.first() - Very Common133134**Use when**: Working with single objects, API responses, first-in-first-out135136```javascript137// Get first item only138const firstItem = $input.first();139const data = firstItem.json;140141return [{142 json: {143 result: processData(data),144 processedAt: new Date().toISOString()145 }146}];147```148149### Pattern 3: $input.item - Each Item Mode Only150151**Use when**: In "Run Once for Each Item" mode152153```javascript154// Current item in loop (Each Item mode only)155const currentItem = $input.item;156157return [{158 json: {159 ...currentItem.json,160 itemProcessed: true161 }162}];163```164165### Pattern 4: $node - Reference Other Nodes166167**Use when**: Need data from specific nodes in workflow168169```javascript170// Get output from specific node171const webhookData = $node["Webhook"].json;172const httpData = $node["HTTP Request"].json;173174return [{175 json: {176 combined: {177 webhook: webhookData,178 api: httpData179 }180 }181}];182```183184**See**: [DATA_ACCESS.md](DATA_ACCESS.md) for comprehensive guide185186---187188## Critical: Webhook Data Structure189190**MOST COMMON MISTAKE**: Webhook data is nested under `.body`191192```javascript193// ❌ WRONG - Will return undefined194const name = $json.name;195const email = $json.email;196197// ✅ CORRECT - Webhook data is under .body198const name = $json.body.name;199const email = $json.body.email;200201// Or with $input202const webhookData = $input.first().json.body;203const name = webhookData.name;204```205206**Why**: Webhook node wraps all request data under `body` property. This includes POST data, query parameters, and JSON payloads.207208**See**: [DATA_ACCESS.md](DATA_ACCESS.md) for full webhook structure details209210---211212## Return Format Requirements213214**CRITICAL RULE**: Always return array of objects with `json` property215216### Correct Return Formats217218```javascript219// ✅ Single result220return [{221 json: {222 field1: value1,223 field2: value2224 }225}];226227// ✅ Multiple results228return [229 {json: {id: 1, data: 'first'}},230 {json: {id: 2, data: 'second'}}231];232233// ✅ Transformed array234const transformed = $input.all()235 .filter(item => item.json.valid)236 .map(item => ({237 json: {238 id: item.json.id,239 processed: true240 }241 }));242return transformed;243244// ✅ Empty result (when no data to return)245return [];246247// ✅ Conditional return248if (shouldProcess) {249 return [{json: processedData}];250} else {251 return [];252}253```254255### Incorrect Return Formats256257```javascript258// ❌ WRONG: Object without array wrapper259return {260 json: {field: value}261};262263// ❌ WRONG: Array without json wrapper264return [{field: value}];265266// ❌ WRONG: Plain string267return "processed";268269// ❌ WRONG: Raw data without mapping270return $input.all(); // Missing .map()271272// ❌ WRONG: Incomplete structure273return [{data: value}]; // Should be {json: value}274```275276**Why it matters**: Next nodes expect array format. Incorrect format causes workflow execution to fail.277278**See**: [ERROR_PATTERNS.md](ERROR_PATTERNS.md) #3 for detailed error solutions279280---281282## Common Patterns Overview283284Based on production workflows, here are the most useful patterns:285286### 1. Multi-Source Data Aggregation287Combine data from multiple APIs, webhooks, or nodes288289```javascript290const allItems = $input.all();291const results = [];292293for (const item of allItems) {294 const sourceName = item.json.name || 'Unknown';295 // Parse source-specific structure296 if (sourceName === 'API1' && item.json.data) {297 results.push({298 json: {299 title: item.json.data.title,300 source: 'API1'301 }302 });303 }304}305306return results;307```308309### 2. Filtering with Regex310Extract patterns, mentions, or keywords from text311312```javascript313const pattern = /\b([A-Z]{2,5})\b/g;314const matches = {};315316for (const item of $input.all()) {317 const text = item.json.text;318 const found = text.match(pattern);319320 if (found) {321 found.forEach(match => {322 matches[match] = (matches[match] || 0) + 1;323 });324 }325}326327return [{json: {matches}}];328```329330### 3. Data Transformation & Enrichment331Map fields, normalize formats, add computed fields332333```javascript334const items = $input.all();335336return items.map(item => {337 const data = item.json;338 const nameParts = data.name.split(' ');339340 return {341 json: {342 first_name: nameParts[0],343 last_name: nameParts.slice(1).join(' '),344 email: data.email,345 created_at: new Date().toISOString()346 }347 };348});349```350351### 4. Top N Filtering & Ranking352Sort and limit results353354```javascript355const items = $input.all();356357const topItems = items358 .sort((a, b) => (b.json.score || 0) - (a.json.score || 0))359 .slice(0, 10);360361return topItems.map(item => ({json: item.json}));362```363364### 5. Aggregation & Reporting365Sum, count, group data366367```javascript368const items = $input.all();369const total = items.reduce((sum, item) => sum + (item.json.amount || 0), 0);370371return [{372 json: {373 total,374 count: items.length,375 average: total / items.length,376 timestamp: new Date().toISOString()377 }378}];379```380381**See**: [COMMON_PATTERNS.md](COMMON_PATTERNS.md) for 10 detailed production patterns382383---384385## Error Prevention - Top 5 Mistakes386387### #1: Empty Code or Missing Return (Most Common)388389```javascript390// ❌ WRONG: No return statement391const items = $input.all();392// ... processing code ...393// Forgot to return!394395// ✅ CORRECT: Always return data396const items = $input.all();397// ... processing ...398return items.map(item => ({json: item.json}));399```400401### #2: Expression Syntax Confusion402403```javascript404// ❌ WRONG: Using n8n expression syntax in code405const value = "{{ $json.field }}";406407// ✅ CORRECT: Use JavaScript template literals408const value = `${$json.field}`;409410// ✅ CORRECT: Direct access411const value = $input.first().json.field;412```413414### #3: Incorrect Return Wrapper415416```javascript417// ❌ WRONG: Returning object instead of array418return {json: {result: 'success'}};419420// ✅ CORRECT: Array wrapper required421return [{json: {result: 'success'}}];422```423424### #4: Missing Null Checks425426```javascript427// ❌ WRONG: Crashes if field doesn't exist428const value = item.json.user.email;429430// ✅ CORRECT: Safe access with optional chaining431const value = item.json?.user?.email || 'no-email@example.com';432433// ✅ CORRECT: Guard clause434if (!item.json.user) {435 return [];436}437const value = item.json.user.email;438```439440### #5: Webhook Body Nesting441442```javascript443// ❌ WRONG: Direct access to webhook data444const email = $json.email;445446// ✅ CORRECT: Webhook data under .body447const email = $json.body.email;448```449450**See**: [ERROR_PATTERNS.md](ERROR_PATTERNS.md) for comprehensive error guide451452---453454## Built-in Functions & Helpers455456### $helpers.httpRequest()457458Make HTTP requests from within code:459460```javascript461const response = await $helpers.httpRequest({462 method: 'GET',463 url: 'https://api.example.com/data',464 headers: {465 'Authorization': 'Bearer token',466 'Content-Type': 'application/json'467 }468});469470return [{json: {data: response}}];471```472473### DateTime (Luxon)474475Date and time operations:476477```javascript478// Current time479const now = DateTime.now();480481// Format dates482const formatted = now.toFormat('yyyy-MM-dd');483const iso = now.toISO();484485// Date arithmetic486const tomorrow = now.plus({days: 1});487const lastWeek = now.minus({weeks: 1});488489return [{490 json: {491 today: formatted,492 tomorrow: tomorrow.toFormat('yyyy-MM-dd')493 }494}];495```496497### $jmespath()498499Query JSON structures:500501```javascript502const data = $input.first().json;503504// Filter array505const adults = $jmespath(data, 'users[?age >= `18`]');506507// Extract fields508const names = $jmespath(data, 'users[*].name');509510return [{json: {adults, names}}];511```512513**See**: [BUILTIN_FUNCTIONS.md](BUILTIN_FUNCTIONS.md) for complete reference514515---516517## Best Practices518519### 1. Always Validate Input Data520521```javascript522const items = $input.all();523524// Check if data exists525if (!items || items.length === 0) {526 return [];527}528529// Validate structure530if (!items[0].json) {531 return [{json: {error: 'Invalid input format'}}];532}533534// Continue processing...535```536537### 2. Use Try-Catch for Error Handling538539```javascript540try {541 const response = await $helpers.httpRequest({542 url: 'https://api.example.com/data'543 });544545 return [{json: {success: true, data: response}}];546} catch (error) {547 return [{548 json: {549 success: false,550 error: error.message551 }552 }];553}554```555556### 3. Prefer Array Methods Over Loops557558```javascript559// ✅ GOOD: Functional approach560const processed = $input.all()561 .filter(item => item.json.valid)562 .map(item => ({json: {id: item.json.id}}));563564// ❌ SLOWER: Manual loop565const processed = [];566for (const item of $input.all()) {567 if (item.json.valid) {568 processed.push({json: {id: item.json.id}});569 }570}571```572573### 4. Filter Early, Process Late574575```javascript576// ✅ GOOD: Filter first to reduce processing577const processed = $input.all()578 .filter(item => item.json.status === 'active') // Reduce dataset first579 .map(item => expensiveTransformation(item)); // Then transform580581// ❌ WASTEFUL: Transform everything, then filter582const processed = $input.all()583 .map(item => expensiveTransformation(item)) // Wastes CPU584 .filter(item => item.json.status === 'active');585```586587### 5. Use Descriptive Variable Names588589```javascript590// ✅ GOOD: Clear intent591const activeUsers = $input.all().filter(item => item.json.active);592const totalRevenue = activeUsers.reduce((sum, user) => sum + user.json.revenue, 0);593594// ❌ BAD: Unclear purpose595const a = $input.all().filter(item => item.json.active);596const t = a.reduce((s, u) => s + u.json.revenue, 0);597```598599### 6. Debug with console.log()600601```javascript602// Debug statements appear in browser console603const items = $input.all();604console.log(`Processing ${items.length} items`);605606for (const item of items) {607 console.log('Item data:', item.json);608 // Process...609}610611return result;612```613614---615616## When to Use Code Node617618Use Code node when:619- ✅ Complex transformations requiring multiple steps620- ✅ Custom calculations or business logic621- ✅ Recursive operations622- ✅ API response parsing with complex structure623- ✅ Multi-step conditionals624- ✅ Data aggregation across items625626Consider other nodes when:627- ❌ Simple field mapping → Use **Set** node628- ❌ Basic filtering → Use **Filter** node629- ❌ Simple conditionals → Use **IF** or **Switch** node630- ❌ HTTP requests only → Use **HTTP Request** node631632**Code node excels at**: Complex logic that would require chaining many simple nodes633634---635636## Integration with Other Skills637638### Works With:639640**n8n Expression Syntax**:641- Expressions use `{{ }}` syntax in other nodes642- Code nodes use JavaScript directly (no `{{ }}`)643- When to use expressions vs code644645**n8n MCP Tools Expert**:646- How to find Code node: `search_nodes({query: "code"})`647- Get configuration help: `get_node_essentials("nodes-base.code")`648- Validate code: `validate_node_operation()`649650**n8n Node Configuration**:651- Mode selection (All Items vs Each Item)652- Language selection (JavaScript vs Python)653- Understanding property dependencies654655**n8n Workflow Patterns**:656- Code nodes in transformation step657- Webhook → Code → API pattern658- Error handling in workflows659660**n8n Validation Expert**:661- Validate Code node configuration662- Handle validation errors663- Auto-fix common issues664665---666667## Quick Reference Checklist668669Before deploying Code nodes, verify:670671- [ ] **Code is not empty** - Must have meaningful logic672- [ ] **Return statement exists** - Must return array of objects673- [ ] **Proper return format** - Each item: `{json: {...}}`674- [ ] **Data access correct** - Using `$input.all()`, `$input.first()`, or `$input.item`675- [ ] **No n8n expressions** - Use JavaScript template literals: `` `${value}` ``676- [ ] **Error handling** - Guard clauses for null/undefined inputs677- [ ] **Webhook data** - Access via `.body` if from webhook678- [ ] **Mode selection** - "All Items" for most cases679- [ ] **Performance** - Prefer map/filter over manual loops680- [ ] **Output consistent** - All code paths return same structure681682---683684## Additional Resources685686### Related Files687- [DATA_ACCESS.md](DATA_ACCESS.md) - Comprehensive data access patterns688- [COMMON_PATTERNS.md](COMMON_PATTERNS.md) - 10 production-tested patterns689- [ERROR_PATTERNS.md](ERROR_PATTERNS.md) - Top 5 errors and solutions690- [BUILTIN_FUNCTIONS.md](BUILTIN_FUNCTIONS.md) - Complete built-in reference691692### n8n Documentation693- Code Node Guide: https://docs.n8n.io/code/code-node/694- Built-in Methods: https://docs.n8n.io/code-examples/methods-variables-reference/695- Luxon Documentation: https://moment.github.io/luxon/696697---698699**Ready to write JavaScript in n8n Code nodes!** Start with simple transformations, use the error patterns guide to avoid common mistakes, and reference the pattern library for production-ready examples.700
Full transparency — inspect the skill content before installing.