G: Hey n8n Automators! 👋 Are you ready to unlock a whole new level of flexibility and power in your workflows? While n8n’s rich set of pre-built nodes handles a massive range of tasks, there are always those unique, complex, or highly customized scenarios that require a little extra magic. That’s where the n8n Code Node comes in! ✨
Think of the Code Node as your personal JavaScript sandbox within n8n. It empowers you to write custom code, manipulate data exactly how you need it, and implement intricate logic that goes beyond standard configurations. If you’ve ever wished n8n could “just do that one thing,” the Code Node is often the answer!
In this deep dive, we’ll explore the incredible potential of the Code Node and walk you through 10 practical, real-world examples that will help you revolutionize your automation workflows. Let’s dive in! 🚀
What is the n8n Code Node? 🤔
At its core, the n8n Code Node allows you to execute JavaScript code. It takes the data flowing into it (known as “items”), performs operations based on your script, and then outputs new or modified items.
How it works:
- Input: The Code Node receives an array of “items.” Each item typically contains a
json
property, which holds your actual data payload, and sometimesbinary
data. - Execution: Your JavaScript code runs. Within this code, you have access to various helper variables and functions provided by n8n.
- Output: Your script must
return
an array of items. These items will then be passed to the next node in your workflow.
Key Variables & Concepts:
items
: An array containing all input items. Each item is an object, typically withitem.json
containing your data.item
: When iterating, this refers to the current item being processed.$node
: Provides access to information about the current node and its execution context (e.g., node name).$workflow
: Provides access to workflow-level data (e.g., workflow name, ID).this
: Refers to the context of the Code Node itself.console.log()
: Your best friend for debugging! Messages appear in the workflow execution logs.
When to use the Code Node?
- When a built-in node doesn’t offer the exact functionality you need.
- For complex data transformations (e.g., parsing irregular formats, combining multiple fields).
- Implementing custom conditional logic that’s too complex for an
IF
node. - Making dynamic API calls with very specific requirements.
- Generating unique IDs, timestamps, or other dynamic data.
- Handling errors in a highly customized way.
Prerequisites & Best Practices Before We Start 💡
- Basic JavaScript Knowledge: You don’t need to be a JS wizard, but understanding variables, arrays, objects, loops (
map
,forEach
,filter
,reduce
), and conditional statements (if/else
) will be immensely helpful. - Debugging with
console.log()
: Seriously, use it! It will save you hours. - Try/Catch Blocks: For external API calls or potentially failing operations within the Code Node, use
try...catch
to handle errors gracefully. - Keep it Focused: While powerful, don’t try to cram an entire application into one Code Node. Break down complex tasks into smaller, manageable Code Nodes or combine them with other n8n nodes.
- Understand
return items;
: Always make sure your Code Node explicitly returns an array of items at the end.
10 Practical n8n Code Node Examples 🛠️
Let’s get our hands dirty with some real-world scenarios! For each example, we’ll explain the problem, show the code, and illustrate the input/output.
1. Custom Data Formatting & Cleaning 🧹
Scenario: You receive contact data with separate first and last names, but your CRM requires a “Full Name” field and all email addresses to be lowercase.
How it works: We’ll iterate through each item, combine firstName
and lastName
into a new fullName
property, and convert the email
to lowercase.
Code:
// Loop through each input item
for (const item of items) {
// Access the JSON data for the current item
const data = item.json;
// Combine first and last name to create a new 'fullName' property
data.fullName = `${data.firstName} ${data.lastName}`;
// Convert the email address to lowercase
data.email = data.email.toLowerCase();
// You can also delete original properties if not needed
// delete data.firstName;
// delete data.lastName;
}
// Return the modified items
return items;
Input Example (JSON):
[
{
"json": {
"firstName": "John",
"lastName": "DOE",
"email": "JOHN.DOE@EXAMPLE.COM"
}
},
{
"json": {
"firstName": "Jane",
"lastName": "Smith",
"email": "JANE.SMITH@domain.org"
}
}
]
Output Example (JSON):
[
{
"json": {
"firstName": "John",
"lastName": "DOE",
"email": "john.doe@example.com",
"fullName": "John DOE"
}
},
{
"json": {
"firstName": "Jane",
"lastName": "Smith",
"email": "jane.smith@domain.org",
"fullName": "Jane Smith"
}
}
]
2. Dynamic API URL Construction 🔗
Scenario: You need to call an external API, but the endpoint or parameters depend on data from a previous node.
How it works: We’ll construct a complete URL using template literals, incorporating dynamic values from the input item. This URL can then be passed to an HTTP Request node.
Code:
// Loop through each input item
for (const item of items) {
const data = item.json;
// Assume data has properties like 'city' and 'apiKey'
const city = data.city;
const apiKey = data.apiKey;
// Construct the dynamic URL for a weather API example
// Encode the city name to handle spaces and special characters
const encodedCity = encodeURIComponent(city);
data.weatherApiUrl = `https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${encodedCity}`;
// You could also directly make the fetch request here if needed (see Example 8)
}
// Return the modified items
return items;
Input Example (JSON):
[
{
"json": {
"city": "New York",
"apiKey": "your_weather_api_key"
}
}
]
Output Example (JSON):
[
{
"json": {
"city": "New York",
"apiKey": "your_weather_api_key",
"weatherApiUrl": "https://api.weatherapi.com/v1/current.json?key=your_weather_api_key&q=New%20York"
}
}
]
3. Complex Conditional Logic & Branching 🚦
Scenario: You need to route items to different paths based on multiple criteria (e.g., user type AND subscription status). An IF
node might get unwieldy.
How it works: We’ll use a switch
statement or chained if/else if
to assign a route
property based on combined conditions. This route
can then be used by an IF
node or a Switch
node.
Code:
// A new array to hold the output items, potentially with different routing properties
const outputItems = [];
for (const item of items) {
const data = item.json;
let routingPath = 'default'; // Default path if no conditions match
if (data.userType === 'premium' && data.subscriptionStatus === 'active') {
routingPath = 'premium_active';
} else if (data.userType === 'standard' && data.subscriptionStatus === 'active') {
routingPath = 'standard_active';
} else if (data.userType === 'guest') {
routingPath = 'guest_user';
} else {
routingPath = 'other_or_inactive';
}
// Add the routing path to the item's JSON
data.routingPath = routingPath;
// Push the modified item to our output array
outputItems.push(item);
}
// Return the items with their assigned routing paths
return outputItems;
Input Example (JSON):
[
{
"json": {
"userType": "premium",
"subscriptionStatus": "active"
}
},
{
"json": {
"userType": "standard",
"subscriptionStatus": "inactive"
}
},
{
"json": {
"userType": "guest"
}
}
]
Output Example (JSON):
[
{
"json": {
"userType": "premium",
"subscriptionStatus": "active",
"routingPath": "premium_active"
}
},
{
"json": {
"userType": "standard",
"subscriptionStatus": "inactive",
"routingPath": "other_or_inactive"
}
},
{
"json": {
"userType": "guest",
"routingPath": "guest_user"
}
}
]
4. Aggregating Data from Multiple Items 📊
Scenario: You have a list of sales records, and you want to calculate the total revenue or sum specific values.
How it works: We’ll use the reduce
method (or a simple loop) to sum up values from all incoming items and then output a single item with the aggregated result.
Code:
// Initialize a variable to store the total
let totalRevenue = 0;
let totalItemsProcessed = 0;
let productList = [];
// Loop through each input item to aggregate data
for (const item of items) {
const data = item.json;
totalRevenue += data.amount; // Summing up the 'amount' field
totalItemsProcessed++;
productList.push({
productName: data.productName,
amount: data.amount,
date: data.date
});
}
// Create a single output item with the aggregated data
const outputItem = {
json: {
totalRevenue: totalRevenue,
numberOfSales: totalItemsProcessed,
aggregatedProducts: productList,
reportGeneratedAt: new Date().toISOString()
}
};
// Return an array containing only the single aggregated item
return [outputItem];
Input Example (JSON):
[
{
"json": {
"productName": "Laptop",
"amount": 1200.00,
"date": "2023-10-26"
}
},
{
"json": {
"productName": "Mouse",
"amount": 25.50,
"date": "2023-10-26"
}
},
{
"json": {
"productName": "Keyboard",
"amount": 75.00,
"date": "2023-10-27"
}
}
]
Output Example (JSON):
[
{
"json": {
"totalRevenue": 1300.50,
"numberOfSales": 3,
"aggregatedProducts": [
{ "productName": "Laptop", "amount": 1200, "date": "2023-10-26" },
{ "productName": "Mouse", "amount": 25.5, "date": "2023-10-26" },
{ "productName": "Keyboard", "amount": 75, "date": "2023-10-27" }
],
"reportGeneratedAt": "2023-10-27T10:30:00.000Z"
}
}
]
5. Advanced Date & Time Calculations ⏰
Scenario: You need to calculate the number of days until an event, determine if a date is in the past, or format a date in a very specific way not offered by built-in nodes.
How it works: We’ll use JavaScript’s built-in Date
object to perform calculations and formatting.
Code:
for (const item of items) {
const data = item.json;
const eventDateString = data.eventDate; // e.g., "2023-11-15"
try {
const eventDate = new Date(eventDateString);
const today = new Date();
// Normalize today to start of day for accurate day difference
today.setHours(0, 0, 0, 0);
eventDate.setHours(0, 0, 0, 0);
const diffTime = eventDate.getTime() - today.getTime();
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); // Convert milliseconds to days
data.daysUntilEvent = diffDays;
data.isPastEvent = diffDays < 0;
// Example of custom date formatting (e.g., "Nov 15, 2023")
const options = { year: 'numeric', month: 'short', day: 'numeric' };
data.formattedEventDate = eventDate.toLocaleDateString('en-US', options);
} catch (error) {
console.error(`Error processing date for item: ${JSON.stringify(data)}`, error);
data.dateProcessingError = `Invalid date format or calculation error: ${error.message}`;
data.daysUntilEvent = null;
data.isPastEvent = null;
data.formattedEventDate = null;
}
}
return items;
Input Example (JSON):
[
{
"json": {
"eventName": "Project Deadline",
"eventDate": "2023-11-15"
}
},
{
"json": {
"eventName": "Past Meeting",
"eventDate": "2023-09-01"
}
}
]
Output Example (JSON):
[
{
"json": {
"eventName": "Project Deadline",
"eventDate": "2023-11-15",
"daysUntilEvent": 19, // (assuming today is Oct 27)
"isPastEvent": false,
"formattedEventDate": "Nov 15, 2023"
}
},
{
"json": {
"eventName": "Past Meeting",
"eventDate": "2023-09-01",
"daysUntilEvent": -56, // (assuming today is Oct 27)
"isPastEvent": true,
"formattedEventDate": "Sep 1, 2023"
}
}
]
6. Custom Error Handling & Reporting 🛑
Scenario: You want to gracefully handle errors for specific items in a batch without stopping the entire workflow, perhaps sending a notification for only the failed ones.
How it works: Use try...catch
blocks around operations that might fail. If an error occurs, you can log it, add an error
property to the item, and continue processing other items. You can then use an IF
node downstream to branch based on the presence of this error
property.
Code:
for (const item of items) {
const data = item.json;
try {
// Simulate an operation that might fail, e.g., parsing a specific field
if (typeof data.valueToProcess !== 'number') {
throw new Error('Value to process is not a number!');
}
data.processedResult = data.valueToProcess * 2;
data.status = 'success'; // Indicate success
} catch (error) {
// Add an 'error' property to the item's JSON
data.status = 'failed';
data.errorMessage = error.message;
console.error(`Error processing item ${JSON.stringify(data)}: ${error.message}`);
// Optionally, store the original error object provided by n8n if available
// if (item.error) {
// data.n8nErrorDetails = item.error;
// }
}
}
return items;
Input Example (JSON):
[
{
"json": {
"id": 1,
"valueToProcess": 10
}
},
{
"json": {
"id": 2,
"valueToProcess": "abc"
}
}
]
Output Example (JSON):
[
{
"json": {
"id": 1,
"valueToProcess": 10,
"processedResult": 20,
"status": "success"
}
},
{
"json": {
"id": 2,
"valueToProcess": "abc",
"status": "failed",
"errorMessage": "Value to process is not a number!"
}
}
]
7. Generating Unique IDs or Random Data 🎲
Scenario: You need to generate a unique identifier for a new record, a random password, or test data.
How it works: Use Math.random()
, Date.now()
, or more robust methods like crypto.randomUUID()
(available in Node.js 14.17.0+ which n8n typically uses) to create unique or random strings/numbers.
Code:
const outputItems = [];
for (const item of items) {
const data = item.json;
// Generate a simple timestamp-based ID
data.simpleId = `id_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
// Generate a UUID (Universally Unique Identifier) if your Node.js version supports it
// This is much more robust for uniqueness
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
data.uniqueId = crypto.randomUUID();
} else {
// Fallback for older Node.js or browser environments
data.uniqueId = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// Generate a random password (e.g., 12 characters alphanumeric)
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()';
let randomPassword = '';
for (let i = 0; i {
const pre = prefix.length ? prefix + '_' : ''; // Use underscore as separator
if (typeof obj[k] === 'object' && obj[k] !== null && !Array.isArray(obj[k])) {
Object.assign(acc, flattenObject(obj[k], pre + k));
} else {
acc[pre + k] = obj[k];
}
return acc;
}, {});
}
const outputItems = [];
for (const item of items) {
const originalData = item.json;
const flattenedData = flattenObject(originalData);
// Replace the original JSON with the flattened version
item.json = flattenedData;
outputItems.push(item);
}
return outputItems;
Input Example (JSON):
[
{
"json": {
"orderId": "ORD789",
"customer": {
"id": "CUST123",
"name": "Alice Wonderland",
"contact": {
"email": "alice@example.com",
"phone": "555-1234"
}
},
"product": [
{"name": "Laptop", "price": 1200}
],
"status": "pending"
}
}
]
Output Example (JSON):
[
{
"json": {
"orderId": "ORD789",
"customer_id": "CUST123",
"customer_name": "Alice Wonderland",
"customer_contact_email": "alice@example.com",
"customer_contact_phone": "555-1234",
"product": [
{"name": "Laptop", "price": 1200}
],
"status": "pending"
}
}
]
(Note: Arrays are intentionally not flattened in this example, as that’s often a separate transformation need)
10. Transforming Lists and Arrays 🔄
Scenario: Your API returns a list of objects, but you only need a specific subset of data from each object, or you want to transform the array into a comma-separated string or a different structure.
How it works: We’ll use array methods like map
or filter
to create new arrays with desired data or join
to convert an array into a string.
Code:
for (const item of items) {
const data = item.json;
// Assume 'data.users' is an array of user objects: [{name: "A", id: 1}, {name: "B", id: 2}]
const users = data.users || [];
// Example 1: Extracting only specific properties (e.g., user names)
data.userNames = users.map(user => user.name); // ["Alice", "Bob"]
// Example 2: Filtering users based on a condition (e.g., active users)
data.activeUsers = users.filter(user => user.status === 'active');
// Example 3: Creating a comma-separated string of user IDs
data.userIdsString = users.map(user => user.id).join(', '); // "101, 102, 103"
// Example 4: Transforming to a custom object structure
data.transformedUsers = users.map(user => ({
display: `${user.name} (${user.id})`,
isActive: user.status === 'active'
}));
}
return items;
Input Example (JSON):
[
{
"json": {
"batchId": "B-001",
"users": [
{"id": 101, "name": "Alice", "status": "active"},
{"id": 102, "name": "Bob", "status": "inactive"},
{"id": 103, "name": "Charlie", "status": "active"}
]
}
}
]
Output Example (JSON):
[
{
"json": {
"batchId": "B-001",
"users": [
{"id": 101, "name": "Alice", "status": "active"},
{"id": 102, "name": "Bob", "status": "inactive"},
{"id": 103, "name": "Charlie", "status": "active"}
],
"userNames": ["Alice", "Bob", "Charlie"],
"activeUsers": [
{"id": 101, "name": "Alice", "status": "active"},
{"id": 103, "name": "Charlie", "status": "active"}
],
"userIdsString": "101, 102, 103",
"transformedUsers": [
{"display": "Alice (101)", "isActive": true},
{"display": "Bob (102)", "isActive": false},
{"display": "Charlie (103)", "isActive": true}
]
}
}
]
Best Practices for Code Node Usage 🧠
- Modularity: If your code gets long, consider breaking it into multiple Code Nodes or defining helper functions outside the main loop/logic if your use case allows.
- Comments: Comment your code! Future you (and anyone else looking at your workflow) will thank you.
- Error Handling: Always anticipate potential issues. Use
try...catch
for robust code, especially when dealing with external data or complex logic. - Performance: For extremely large datasets (thousands/millions of items), be mindful of complex operations within the Code Node, as JavaScript execution can be CPU-intensive.
- Testing: Thoroughly test your Code Node with various inputs, including edge cases, empty data, and malformed data. The “Test workflow” feature is your friend!
- Don’t Overuse: While powerful, the Code Node isn’t always the answer. If a built-in node (like Set, Move & Rename, Split In Batches, etc.) can do the job simply, use it! It’s generally more readable and maintainable.
Conclusion 🎉
The n8n Code Node is truly a game-changer for anyone looking to push the boundaries of their automation workflows. By leveraging the power of JavaScript, you can tackle complex data transformations, implement custom logic, and interact with APIs in ways that would be impossible with standard nodes alone.
From simple data cleaning to intricate API orchestration, the 10 examples above are just the tip of the iceberg. The more you experiment and understand your data, the more scenarios you’ll discover where the Code Node becomes your go-to solution.
So, go ahead – embrace your inner data wizard, start experimenting with the Code Node, and watch your n8n workflows transform from powerful to truly unstoppable! Happy automating! ✨