Code Node in n8n Automation: 5 JavaScript Array Patterns
Building reliable n8n automation requires understanding how data moves through workflows, especially when visual nodes cannot handle custom transformations. Visual builders make simple API triggers straightforward. However, the moment an external webhook delivers deeply nested objects, inconsistent array formats, or unkeyed records, standard drag-and-drop nodes fall short. That is where the Code node becomes the most critical component in your workspace.
Many engineers who start learning n8n search for full courses or programming bootcamps just to handle basic payloads. In practice, you do not need to master full-stack JavaScript to run production workflows. You only need a firm grasp of how n8n represents items in memory and a handful of targeted data transformation patterns. This guide walks through the exact mechanics of n8n data structures, five concrete JavaScript patterns for the Code node, and how to configure them without causing execution stalls.
How Data Structures Work in n8n Automation
Before writing a single line of JavaScript in n8n, you must understand the foundational contract between nodes. Unlike standard scripting environments where a function receives arbitrary arguments, every node in n8n expects and outputs an array of objects. Each object inside this array must contain a top-level key named json.
When an incoming HTTP request arrives at a Webhook node, n8n wraps the incoming body into this standard structure. If a webhook payload delivers a single object with three fields, n8n structures it internally like this:
[
{
"json": {
"orderId": "ORD-9821",
"status": "completed",
"total": 142.50
}
}
]If you return data from a Code node that does not match this envelope, n8n immediately throws an execution error. A frequent mistake made by teams experimenting with a self hosted n8n instance is returning a raw JavaScript array of primitives or a bare object. The workflow halts because downstream nodes do not recognize the schema.
The Code node supports two execution modes in its configuration panel:
- Run Once for All Items: The script executes a single time. It receives the entire batch of items in an array called
$input.all(). This mode is mandatory whenever you need to aggregate values, sort lists, group items by a key, or split nested arrays into discrete items. - Run Once for Each Item: The script executes iteratively for every item passed into the node. You access the current item via
$input.itemand its JSON payload via$input.item.json. This mode is best suited for isolated string formatting, date parsing, or standalone math calculations.
Choosing the correct execution mode directly impacts your workflow speed. Running a Code node once across 5,000 items is drastically faster than executing the node sandbox 5,000 separate times.
5 Essential JavaScript Patterns for n8n Automation
These five patterns solve the most common data transformation challenges encountered in enterprise production environments. Each pattern runs in the Run Once for All Items mode to ensure maximum throughput and compatibility with downstream nodes.
1. Unpacking Nested Arrays into Discrete Execution Items
Third-party APIs often bundle child line items inside a parent record. For instance, an e-commerce webhook or an invoicing endpoint might send one order object that contains an array of ten purchase items. Downstream nodes—such as a database inserter or a fulfillment sync—need each item as its own discrete n8n item.
Here is the standard pattern to flatten nested items while preserving parent metadata:
const items = $input.all();
const output = [];
for (const item of items) {
const parentOrder = item.json.orderId;
const customerEmail = item.json.customer.email;
const lineItems = item.json.line_items || [];
for (const line of lineItems) {
output.push({
json: {
orderId: parentOrder,
customerEmail: customerEmail,
sku: line.sku,
quantity: line.quantity,
unitPrice: line.price
}
});
}
}
return output;This script extracts each child item, attaches the essential parent context, and returns a clean array where every record has the mandatory json key.
2. Deduplicating Records by a Unique Composite Key
When polling APIs or consuming webhooks during high-traffic events, workflows often receive duplicate records. The visual Remove Duplicates node works well for simple primitive comparisons, but it struggles when deduplication requires composite business logic.
You can use a JavaScript Map inside the Code node to deduplicate thousands of records in linear time:
const items = $input.all();
const uniqueRecords = new Map();
for (const item of items) {
// Create a composite key based on multiple fields
const compositeKey = `${item.json.tenantId}_${item.json.email.toLowerCase()}`;
if (!uniqueRecords.has(compositeKey)) {
uniqueRecords.set(compositeKey, item);
} else {
// Optional: Keep the record with the most recent timestamp
const existing = uniqueRecords.get(compositeKey);
if (new Date(item.json.updatedAt) > new Date(existing.json.updatedAt)) {
uniqueRecords.set(compositeKey, item);
}
}
}
return Array.from(uniqueRecords.values());This pattern processes large payloads without noticeable CPU latency. It ensures that duplicate webhooks do not trigger repetitive database writes or duplicate customer emails.
3. Grouping and Aggregating Items by Category
The inverse of flattening is aggregation. Suppose an earlier stage in your workflow retrieves a flat list of 200 operational expenses across several departments. Before sending an executive summary to Slack or compiling an end-of-month report, you must group those expenses by department and calculate totals.
const items = $input.all();
const aggregated = {};
for (const item of items) {
const dept = item.json.department || 'Unassigned';
const amount = Number(item.json.amount) || 0;
if (!aggregated[dept]) {
aggregated[dept] = {
department: dept,
totalSpend: 0,
transactionCount: 0
};
}
aggregated[dept].totalSpend += amount;
aggregated[dept].transactionCount += 1;
}
// Transform the aggregated hash map back into n8n item format
return Object.values(aggregated).map(group => ({
json: {
department: group.department,
totalSpend: Math.round(group.totalSpend * 100) / 100,
transactionCount: group.transactionCount,
averageTicket: Math.round((group.totalSpend / group.transactionCount) * 100) / 100
}
}));Downstream nodes receive clean, pre-calculated metrics ready for notification or database insertion without needing multi-step math nodes.
4. Filtering and Sanitizing Incoming Webhook Payloads
External payloads often arrive with messy metadata, null values, or sensitive customer details that should never enter database records. While the visual Filter node can check conditions, it cannot easily strip null keys or trim strings across deeply nested fields.
Use this sanitization pattern to strip empty strings, clean whitespace, and drop disallowed attributes:
const items = $input.all();
const disallowedKeys = ['creditCardNumber', 'internalToken', 'debugTrace'];
return items.map(item => {
const cleanData = {};
for (const [key, value] of Object.entries(item.json)) {
if (disallowedKeys.includes(key)) continue;
if (value === null || value === undefined) continue;
if (typeof value === 'string') {
cleanData[key] = value.trim();
} else {
cleanData[key] = value;
}
}
return { json: cleanData };
});This guarantees that downstream database queries only receive sanitized, valid values, reducing schema validation errors.
5. Joining Two Data Streams Without the Merge Node
While n8n provides a native Merge node, complex multi-field joins with fallback logic can become difficult to configure visually. The Code node allows you to pull data directly from any prior node in your workflow canvas using the $('Node Name').all() syntax.
// Pull current items and historical items from an earlier node
const currentLeads = $input.all();
const existingCrmContacts = $('Fetch Existing CRM Contacts').all();
// Index existing contacts by email for O(1) lookup
const contactMap = new Map();
for (const contact of existingCrmContacts) {
if (contact.json.email) {
contactMap.set(contact.json.email.toLowerCase(), contact.json.id);
}
}
return currentLeads.map(lead => {
const leadEmail = (lead.json.email || '').toLowerCase();
const matchedCrmId = contactMap.get(leadEmail) || null;
return {
json: {
...lead.json,
crmContactId: matchedCrmId,
isExistingCustomer: matchedCrmId !== null
}
};
});This pattern eliminates branch clutter on your canvas, turning complex conditional merge logic into a straightforward ten-line script.
Tip: Always test Code node scripts using the "Test step" button with mock data before activating your workflow. You can view the input and output JSON side-by-side to verify the envelope structure.
Structuring Custom Tool Outputs for AI Agent Nodes
Modern workflows frequently connect LangChain-powered AI Agent nodes with custom data sources. When an AI Agent invokes a Custom n8n Tool, the tool's output must be predictable and clean. If the tool returns irregular JSON or unformatted text, the language model can hallucinate parameters or fail to parse the tool output.
When building custom tools using a Code node inside an AI Agent flow, follow these three rules:
- Return Plain JSON Strings or Concise Dictionaries: Language models process tokens. Avoid returning raw API payloads containing 80 unused fields. Trim the payload down to the 3 or 4 fields the LLM specifically requested.
- Handle Missing Values Gracefully: If an API lookup returns empty results, do not allow the Code node to throw an unhandled exception. Return a structured fallback such as
{ "found": false, "message": "No matching user records found." }. - Cast Numbers and Booleans Explicitly: LLM tool callers sometimes pass numeric inputs as strings (e.g.,
"42"instead of42). Normalize types inside your Code node before invoking downstream calculations.
Here is an example of an AI tool script that formats inventory data specifically for consumption by an AI Agent node:
const items = $input.all();
if (items.length === 0) {
return [{
json: {
status: 'error',
message: 'Product SKU was not found in inventory.'
}
}];
}
const product = items[0].json;
return [{
json: {
sku: product.sku,
inStock: Boolean(product.stock_quantity > 0),
availableQuantity: Number(product.stock_quantity),
warehouseLocation: product.warehouse_code || 'Standard Central'
}
}];Clean tool outputs ensure that your AI Agent makes deterministic decisions without wasting context window tokens on redundant JSON keys.
Debugging Memory and Execution Errors in Code Nodes
When executing JavaScript on large arrays, memory management becomes critical. In an unoptimized environment, running loops over tens of thousands of records can trigger ERR_OUT_OF_MEMORY crashes that take down the entire n8n process.
fs or child_process are disabled by default for security reasons. Rely strictly on standard ECMAScript operations and built-in n8n utility functions.To avoid memory spikes and execution timeouts:
- Avoid Cloning Unnecessary Objects: Deep cloning large objects using
JSON.parse(JSON.stringify(data))inside a loop creates massive garbage collection pressure. Only extract the specific fields you need. - Batch Massive Datasets with the Split in Batches Node: If you are processing 50,000 items, do not dump them all into a single Code node execution. Use a Split in Batches node to chunk the incoming data into sets of 500 or 1,000 items.
- Check Execution Logs Frequently: When a workflow fails silently, inspect the instance logs. On n8nautomation.cloud, users have access to real-time instance logs directly inside the dashboard, making it simple to spot syntax errors, unhandled rejections, and memory spikes.
Running Custom JavaScript: Self-Hosting vs Dedicated Hosting
Running code-heavy workflows highlights the operational differences between hosting environments. When developers investigate how to install n8n on a local machine or a cheap virtual machine, they often begin with a basic Docker command. However, self-hosting at scale introduces hidden infrastructure overhead.
Maintaining a self hosted n8n instance requires managing Docker volumes, provisioning SSL certificates via reverse proxies like Traefik or Caddy, configuring PostgreSQL databases, applying security patches, and monitoring memory thresholds. If a heavy Code node runs out of RAM during an unattended weekend run, the container crashes, and incoming webhooks drop.
For teams seeking the best n8n hosting experience without managing Linux servers, n8n managed hosting provides a balanced solution. Instead of paying hefty server bills or babysitting infrastructure, n8nautomation.cloud delivers dedicated, high-performance n8n instances starting at just $4/month. This makes it an ideal option for anyone looking for low cost n8n hosting with production-level reliability.
With n8n hosting on n8nautomation.cloud, you receive:
- Dedicated Instances: Every user gets their own dedicated instance with a custom subdomain (e.g.,
yourname.n8nautomation.cloud), with the ability to change the domain at any time. - Full Community Node Freedom: Run the complete n8n Community Edition with 400+ native integrations and community-contributed nodes.
- Automated Backups and 24/7 Uptime: Instances are monitored continuously so memory-heavy executions do not leave your production pipelines offline.
- Built-in Migration Tool: Moving from an existing server is effortless. Our migration tool takes the URL and API keys for both your old n8n setup and your new n8nautomation.cloud instance, migrating workflows in seconds while keeping credentials safely isolated.
- Live Log Access: Access internal n8n execution logs directly from the dashboard to debug complex JavaScript transformations and API errors without needing SSH access.
By pairing efficient JavaScript patterns in your Code nodes with an optimized hosting platform, your automation pipelines stay fast, predictable, and resilient under any production workload.
Related Posts
Why Developers Switch to n8n Automation: Code Node & Custom APIs
Discover why engineering teams choose n8n automation over rigid SaaS tools. Learn how Code nodes, custom APIs, and managed hosting streamline complex workflows.
Build an AI Router in n8n Automation with OpenAI and Switch Nodes
Build an intelligent webhook router in n8n automation using OpenAI and Switch nodes to classify unstructured payloads, eliminate manual triage, and scale fast.
Running High-Volume n8n Automation with the Webhook Node
Learn how to architect high-volume n8n automation using the Webhook node, manage memory, cut execution costs, and run production workflows without limits.