The Code Node fills gaps where built-in nodes fall short. You write custom JavaScript or Python, process data however you need, and pass it to the next step. This article gives you copy-paste examples for the most common use cases.
When to Use the Code Node
Built-in nodes handle standard operations. The Code Node handles everything else:
-
Transforming data structures that don't match what the next node expects
-
Filtering arrays based on complex conditions
-
Calling APIs that don't have a dedicated n8n integration
-
Working with dates, strings, or numbers in custom ways
-
Generating binary files like CSVs
If you're doing something a built-in node can do, use the built-in node. Code Nodes add complexity. Use them when you need logic that doesn't exist elsewhere.
JavaScript vs Python in the Code Node
Both languages work. JavaScript has better support in n8n's ecosystem - more examples, more community answers, and the expression syntax throughout n8n is JavaScript-based anyway.
| Feature | JavaScript | Python |
|---|---|---|
| Data access | $input.all() | _input.all() |
| Return format | return items | return items |
| External modules | Limited built-ins | Limited built-ins |
| Community examples | Extensive | Growing |
| Expression compatibility | Native | Requires context switching |
Python works fine for data processing. If you're more comfortable with Python, use it. But expect fewer examples to copy from.
Understanding $input and $items
This trips up most people. Here's the difference:
$input.all() - Returns all items from the previous node as an array. Each item has a json property containing the data.
$input.first() - Returns only the first item.
$input.item - In "Run Once for Each Item" mode, gives you the current item being processed.
Common mistake: trying to access $input.all().json directly. That doesn't work because $input.all() returns an array. You need $input.all()[0].json for the first item's data, or loop through the array.
// Wrong
const data = $input.all().json;
// Right
const items = $input.all();
const firstItemData = items[0].json;
In Python, replace $input with _input. Same methods, different prefix.
Example 1: Transform Data Structure
You have user records and need to restructure them for a CRM import.
Input:
[{"json": {"first": "John", "last": "Doe", "email": "john@example.com"}}]
JavaScript:
const items = $input.all();
return items.map(item => ({
json: {
fullName: `${item.json.first} ${item.json.last}`,
contactEmail: item.json.email,
source: "n8n-import"
}
}));
Output:
[{"json": {"fullName": "John Doe", "contactEmail": "john@example.com", "source": "n8n-import"}}]
The key: always return an array of objects, each with a json property.
Example 2: Filter Arrays by Condition
Remove items that don't meet criteria. The Filter node works for simple cases, but complex logic needs code.
JavaScript - Filter adults only:
const items = $input.all();
return items.filter(item => item.json.age >= 18);
JavaScript - Multiple conditions:
const items = $input.all();
return items.filter(item => {
const isActive = item.json.status === 'active';
const hasEmail = item.json.email && item.json.email.includes('@');
const recentLogin = new Date(item.json.lastLogin) > new Date('2026-01-01');
return isActive && hasEmail && recentLogin;
});
Python equivalent:
items = _input.all()
return [item for item in items if item.json.get('age', 0) >= 18]
Example 3: Format Dates
Date handling is a constant pain point. n8n passes dates as strings, and downstream systems want specific formats.
JavaScript - ISO to readable:
const items = $input.all();
return items.map(item => {
const date = new Date(item.json.createdAt);
return {
json: {
...item.json,
formattedDate: date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
})
}
};
});
JavaScript - Calculate age from birthdate:
const items = $input.all();
return items.map(item => {
const birth = new Date(item.json.birthdate);
const today = new Date();
let age = today.getFullYear() - birth.getFullYear();
const monthDiff = today.getMonth() - birth.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--;
}
return {
json: { ...item.json, age }
};
});
Example 4: Call External APIs
When there's no built-in node for an API, use fetch in the Code Node.
JavaScript - Simple GET request:
const response = await fetch('https://api.genderize.io?name=john');
const data = await response.json();
return [{ json: data }];
JavaScript - POST with headers:
const items = $input.all();
const results = [];
for (const item of items) {
const response = await fetch('https://api.example.com/enrich', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
},
body: JSON.stringify({ email: item.json.email })
});
const enriched = await response.json();
results.push({
json: { ...item.json, ...enriched }
});
}
return results;
Note: For APIs you call frequently, check if a community node exists first. Code Node API calls are harder to debug.
Example 5: Parse Nested JSON
APIs often return deeply nested structures. Flatten them for easier processing.
JavaScript:
const items = $input.all();
return items.map(item => {
const data = item.json;
return {
json: {
id: data.id,
userName: data.user?.profile?.name || 'Unknown',
userEmail: data.user?.contact?.email || null,
orderTotal: data.order?.payment?.amount || 0,
orderCurrency: data.order?.payment?.currency || 'USD'
}
};
});
The optional chaining (?.) prevents errors when nested properties don't exist.
Example 6: Aggregate and Calculate Statistics
Process all items to produce summary data - averages, totals, counts.
JavaScript:
const items = $input.all();
const ages = items.map(item => item.json.age).filter(a => typeof a === 'number');
const stats = {
count: ages.length,
total: ages.reduce((sum, age) => sum + age, 0),
average: ages.length > 0 ? ages.reduce((sum, age) => sum + age, 0) / ages.length : 0,
min: ages.length > 0 ? Math.min(...ages) : null,
max: ages.length > 0 ? Math.max(...ages) : null
};
return [{ json: stats }];
This returns a single item with the aggregated results, not one item per input.
Example 7: Work with Binary Data - CSV Export
Generate a CSV file from your data.
JavaScript:
const items = $input.all();
// Build CSV content
const headers = ['name', 'email', 'age'];
const rows = items.map(item =>
headers.map(h => `"${(item.json[h] || '').toString().replace(/"/g, '"')}"`).join(',')
);
const csv = [headers.join(','), ...rows].join('\n');
// Return as binary
return [{
json: {},
binary: {
data: await this.helpers.prepareBinaryData(
Buffer.from(csv, 'utf-8'),
'export.csv',
'text/csv'
)
}
}];
The binary property makes the file available for download or sending via email/storage nodes.
Example 8: Deduplicate by Key
Remove duplicate entries based on a specific field.
JavaScript:
const items = $input.all();
const seen = new Set();
const unique = [];
for (const item of items) {
const key = item.json.email; // dedupe by email
if (!seen.has(key)) {
seen.add(key);
unique.push(item);
}
}
return unique;
Example 9: Batch Items into Groups
Split a large array into smaller batches for rate-limited APIs.
JavaScript:
const items = $input.all();
const batchSize = 10;
const batches = [];
for (let i = 0; i < items.length; i += batchSize) {
batches.push({
json: {
batchNumber: Math.floor(i / batchSize) + 1,
items: items.slice(i, i + batchSize).map(item => item.json)
}
});
}
return batches;
Each output item contains an array of up to 10 original items.
Example 10: Conditional Field Mapping
Map fields differently based on data values.
JavaScript:
const items = $input.all();
return items.map(item => {
const data = item.json;
let priority, handler;
if (data.revenue > 100000) {
priority = 'high';
handler = 'enterprise-team';
} else if (data.revenue > 10000) {
priority = 'medium';
handler = 'sales-team';
} else {
priority = 'low';
handler = 'self-serve';
}
return {
json: {
...data,
priority,
handler,
processedAt: new Date().toISOString()
}
};
});
Common Errors and Fixes
"Cannot read property 'json' of undefined" You're accessing an item that doesn't exist. Check if your input array is empty before processing.
const items = $input.all();
if (items.length === 0) {
return [{ json: { error: 'No input data' } }];
}
"items is not iterable" Your return value isn't an array. The Code Node must return an array, even for single items.
// Wrong
return { json: { result: 'done' } };
// Right
return [{ json: { result: 'done' } }];
Output shows as array in next node
The Code Node output displays differently than you might expect. Each returned array item becomes a separate n8n item. If you return [{json: {data: [1,2,3]}}], that's one item with an array inside its json - not three items.
Python _input not working
Make sure you selected Python in the Code Node language dropdown. The default is JavaScript.
FAQ
Can I use npm packages in the Code Node?
Not directly. The Code Node has access to built-in Node.js modules and a few extras (like crypto), but you can't import arbitrary npm packages. For external libraries, you'd need to self-host n8n and modify the configuration.
Should I use "Run Once for All Items" or "Run Once for Each Item"? Use "Run Once for All Items" when you need to process items together - aggregations, deduplication, batching. Use "Run Once for Each Item" when each item is independent and you want simpler code that doesn't need to loop.
How do I debug Code Node errors?
Add console.log() statements - they appear in the execution log. For complex debugging, return intermediate values as json output to inspect them, then fix your logic.
Is there a character or complexity limit? No hard character limit, but extremely long or computationally heavy code will timeout. If you're writing hundreds of lines, consider whether you should split the logic across multiple nodes.
Can I access data from nodes other than the previous one?
Yes. Use $('NodeName').all() to get output from any earlier node by its name. Useful for merging data from different branches.
Need help building n8n workflows with custom logic? n8n Logic builds automation systems that handle complex data processing, API integrations, and business workflows.