Complete "Lesson 3: Conditional Logic with IF and Switch Nodes" first to unlock this lesson.Go to previous lesson

Introduction

The Code node is one of the most powerful tools in n8n. When built-in nodes like Set, Edit Fields, or Split Out can't quite do what you need, the Code node lets you write real JavaScript to transform data exactly the way you want. It runs in a sandboxed Node.js environment and has direct access to n8n's item structure, giving you full control over your workflow's data.

This lesson focuses on three practical use cases: manipulating arrays, formatting strings, and computing new fields from existing ones.

How the Code Node Works

The Code node operates on the items array that flows through your workflow. Each item has an object called json that holds its data. When you open the Code node, you write a function body — n8n wraps it automatically, so you don't need to define a function yourself.

There are two execution modes. "Run Once for All Items" gives you access to all items at once via the items variable. "Run Once for Each Item" gives you a single item variable. The default and most flexible mode is "Run Once for All Items", which is what this lesson focuses on.

In this mode, your code must return an array of objects shaped like this:

javascript
return [
{ json: { fieldName: value } },
{ json: { fieldName: value } }
];

Every object in the returned array becomes one output item. If you return an empty array, zero items pass forward.

flowchart showing items array entering Code node, JavaScript logic applied, transformed items array exiting

Array Manipulation

Suppose an upstream node gives you a list of orders, and each item has a products field that is an array of objects. You want to flatten the list so each product becomes its own item.

javascript
const result = [];
for (const item of items) {
const orderId = item.json.orderId;
const products = item.json.products;
for (const product of products) {
result.push({
json: {
orderId,
productName: product.name,
quantity: product.qty,
}
});
}
}
return result;

If you started with 3 order items, each containing 4 products, you end up with 12 output items. This is something Split Out can do for simple cases, but the Code node lets you carry along computed context from the parent item at the same time.

To do the reverse — group multiple items into one — you can use reduce:

javascript
const grouped = items.reduce((acc, item) => {
const key = item.json.category;
if (!acc[key]) acc[key] = [];
acc[key].push(item.json.productName);
return acc;
}, {});
return Object.entries(grouped).map(([category, products]) => ({
json: { category, products }
}));

String Formatting

String transformations are a common reason to reach for the Code node. The Expression editor handles simple cases, but multi-step formatting is cleaner in code.

Here's an example that normalizes a name field — trims whitespace, converts to title case, and builds a display label:

javascript
function toTitleCase(str) {
return str
.trim()
.toLowerCase()
.replace(/\b\w/g, (char) => char.toUpperCase());
}
return items.map((item) => {
const raw = item.json.fullName || '';
const formatted = toTitleCase(raw);
const initials = formatted
.split(' ')
.map((w) => w[0])
.join('');
return {
json: {
...item.json,
fullName: formatted,
initials,
displayLabel: `${formatted} (${initials})`,
}
};
});

Using the spread operator ...item.json keeps all existing fields and adds the new ones on top of them, so downstream nodes still see the original data.

Computing New Fields

The Code node is ideal when a new field depends on a calculation across multiple existing fields — things like totals, age from a birthdate, or status flags based on business rules.

javascript
return items.map((item) => {
const { unitPrice, quantity, discountPercent } = item.json;
const subtotal = unitPrice * quantity;
const discountAmount = subtotal * (discountPercent / 100);
const total = subtotal - discountAmount;
const status =
total > 1000 ? 'high_value'
: total > 200 ? 'standard'
: 'low_value';
return {
json: {
...item.json,
subtotal: +subtotal.toFixed(2),
discountAmount: +discountAmount.toFixed(2),
total: +total.toFixed(2),
status,
}
};
});

Note the use of +value.toFixed(2) — toFixed returns a string, so the unary + converts it back to a number. This matters because downstream nodes doing math or comparisons will behave differently on strings versus numbers.

diagram showing input item fields (unitPrice, quantity, discountPercent) flowing into Code node logic, producing computed output fields (subtotal, discountAmount, total, status)

Common Mistakes

Forgetting to wrap output in json is the most frequent error. Returning { name: 'Alice' } instead of { json: { name: 'Alice' } } will cause n8n to throw an error or silently drop data.

Mutating item.json directly instead of spreading it can cause unexpected side effects in some n8n versions — always build a new object.

Using await without marking the Code node as async-capable: if you need to call a built-in helper like $node or use async operations, make sure your logic accounts for the execution mode. Standard synchronous transformations like the examples above don't need any special setup.

Finally, the Code node does not have access to external npm packages by default in n8n Cloud. On self-hosted n8n you can allowlist packages, but write your code to be portable unless you control the deployment.

Summary

The Code node gives you a full JavaScript environment to handle transformations that built-in nodes can't express cleanly. The key habit is to always return an array of { json: ... } objects, spread existing fields when you only want to add new ones, and choose "Run Once for All Items" when the transformation involves reshaping the collection itself.

Lesson practice

Lesson Checkpoint

Review what you learned and get feedback on your work.

0/1
Answered · 0/1