금. 8월 15th, 2025

G: Are you ready to unlock the true power of n8n workflows? While n8n offers a fantastic array of built-in nodes for almost every automation need, there are times when you need that extra sprinkle of custom logic, intricate data manipulation, or highly specific conditional routing. This is precisely where the mighty Code Node comes into play! 🚀

The n8n Code Node allows you to execute arbitrary JavaScript code directly within your workflows, transforming a powerful automation tool into an incredibly flexible programming canvas. If you’ve ever felt limited by the standard nodes, prepare to have your mind blown.

In this comprehensive guide, we’ll deep dive into what the n8n Code Node is, how it works, best practices for using it, and arm you with 10 essential, real-world examples that will help you master its capabilities. Let’s get coding! 💻✨


1. What Exactly is the n8n Code Node? 🤔

At its heart, the n8n Code Node is a secure JavaScript sandbox where you can write and execute your own custom code. Think of it as a mini-JavaScript interpreter embedded directly into your n8n workflow.

Why is it essential?

  • Custom Logic: When built-in nodes can’t handle your specific business rules.
  • Complex Data Transformation: Reshaping, combining, or filtering data in ways that are too intricate for Set or Split In Batches nodes.
  • Dynamic Value Generation: Creating unique IDs, specific timestamps, or custom strings on the fly.
  • Advanced Error Handling: Implementing custom fallbacks or logging.
  • Conditional Processing: More sophisticated branching logic than a simple If node.

When to use it vs. other nodes:

  • Use Code Node when: You need custom JavaScript logic, complex data transformations across multiple items, or highly dynamic data generation.
  • Prefer other nodes when:
    • Set Node: Simple key-value mapping, basic string operations, or simple calculations.
    • HTTP Request Node: Making API calls (it handles authentication, retries, etc., much better).
    • If Node: Simple true/false branching based on a single condition.
    • Split In Batches/Item Lists: Basic array manipulation or looping over items.

2. The Core Concepts: Anatomy of a Code Node 🔬

To effectively use the Code Node, you need to understand how it interacts with the data flowing through your n8n workflow.

2.1. Input Data: The items Variable 📦

When data enters the Code Node, it’s provided as a JavaScript array named items. Each element in this items array represents a single “item” from the previous node.

Each item object typically has:

  • json: An object containing the primary data of the item. This is where most of your data will reside.
  • binary (optional): An object containing binary data (e.g., files).

Example items structure:

[
  {
    json: {
      id: 1,
      name: "Alice",
      email: "alice@example.com",
      status: "active"
    },
    // binary: { ... } (if binary data exists)
  },
  {
    json: {
      id: 2,
      name: "Bob",
      email: "bob@example.com",
      status: "inactive"
    }
  }
]

To access data from an item, you’ll typically use item.json.propertyName. For example, items[0].json.name would give you “Alice”.

2.2. Output Data: The return Statement 📤

The Code Node expects you to return an array of objects. This array will become the items input for the next node in your workflow. If you want to pass all original items through unchanged, you simply return items;.

Crucially: Even if you’re processing a single item, your return statement must return an array. If you transform one item into a new single item, you’d return [newItem].

2.3. Debugging: console.log() 🐛

Just like in standard JavaScript development, console.log() is your best friend for debugging. Any output from console.log() will appear in the “Output” section of the Code Node when you test it manually, or in the execution logs.

2.4. Asynchronous Operations: async/await

If your code needs to perform asynchronous operations (e.g., simulate a delay with setTimeout, or if you were somehow integrating with a library that returned Promises), you can use async/await. However, for most common data manipulation tasks, synchronous code is sufficient.

2.5. Error Handling: try...catch 🛑

Robust code includes error handling. Wrap your logic in try...catch blocks to gracefully manage errors and prevent your workflow from failing unexpectedly.


3. Best Practices for Mastering the Code Node 🌟

Before we dive into examples, let’s establish some ground rules for writing effective and maintainable Code Node scripts:

  1. Keep it Focused: Each Code Node should ideally perform one specific, well-defined task. Avoid cramming too much unrelated logic into a single node.
  2. Comment Your Code: Use comments (// or /* ... */) to explain complex logic, variable purposes, and any assumptions. Your future self (and others) will thank you!
  3. Test Thoroughly: Use “Test Workflow” or “Execute Workflow” with sample data to ensure your code behaves as expected in various scenarios (e.g., missing data, empty arrays).
  4. Handle Edge Cases: What happens if a required property is missing? What if an array is empty? Account for these scenarios.
  5. Use Existing Nodes First: If a standard n8n node can achieve your goal, use it! They are often more performant and easier to maintain for simpler tasks.
  6. Immutable Operations (where possible): When modifying items, it’s often safer to create new items or new objects rather than directly mutating the input items. This makes debugging easier.
  7. No External NPM Modules: A crucial limitation: you cannot require or import external npm packages within the Code Node. It’s pure, vanilla JavaScript.

4. 10 Core Usage Examples: Unleash the Power! 🔥

Let’s get practical! Here are 10 essential use cases that demonstrate the versatility of the n8n Code Node. For each, we’ll provide the problem, the code, and an explanation.

Example Setup for Input Data:

For most examples, assume the previous node outputs the following data:

[
  {
    "json": {
      "id": 101,
      "firstName": "Alice",
      "lastName": "Smith",
      "email": "alice.smith@example.com",
      "age": 30,
      "role": "Admin",
      "isActive": true,
      "score": 85.5,
      "tags": ["marketing", "sales"]
    }
  },
  {
    "json": {
      "id": 102,
      "firstName": "Bob",
      "lastName": "Johnson",
      "email": "bob.j@example.com",
      "age": 24,
      "role": "User",
      "isActive": false,
      "score": 70.2,
      "tags": ["support"]
    }
  },
  {
    "json": {
      "id": 103,
      "firstName": "Charlie",
      "lastName": "Brown",
      "email": "charlie.b@example.com",
      "age": 45,
      "role": "Admin",
      "isActive": true,
      "score": 92.1,
      "tags": ["finance", "hr"]
    }
  }
]

4.1. Example 1: Simple Data Transformation & Renaming 🪄

Problem: Combine firstName and lastName into a new fullName field and convert email to lowercase.

return items.map(item => {
  const firstName = item.json.firstName || '';
  const lastName = item.json.lastName || '';
  const email = item.json.email || '';

  // Create a new object with transformed data
  return {
    json: {
      ...item.json, // Keep all existing properties
      fullName: `${firstName} ${lastName}`,
      email: email.toLowerCase()
    }
  };
});

Explanation: We use items.map() to iterate over each item. For each item, we create a fullName by concatenating first and last names and convert the email to lowercase. The ...item.json syntax is a spread operator that copies all original properties, ensuring no data is lost. We then overwrite or add the new fields.

Sample Output (for first item):

{
  "id": 101,
  "firstName": "Alice",
  "lastName": "Smith",
  "email": "alice.smith@example.com", // This will be "alice.smith@example.com" in the actual output due to .toLowerCase()
  "age": 30,
  "role": "Admin",
  "isActive": true,
  "score": 85.5,
  "tags": ["marketing", "sales"],
  "fullName": "Alice Smith"
}

4.2. Example 2: Conditional Filtering Based on Complex Logic 🕵️‍♀️

Problem: Filter out users who are “inactive” AND have an age less than 25.

return items.filter(item => {
  const isActive = item.json.isActive;
  const age = item.json.age;

  // Keep items that are active OR (inactive but age >= 25)
  // This means: (true OR true) is true, (true OR false) is true, (false OR true) is true, (false OR false) is false.
  // We want to remove (isActive === false && age < 25)
  return !(isActive === false && age  item.json.isActive);
const totalScore = activeUsers.reduce((sum, item) => sum + (item.json.score || 0), 0);
const averageScore = activeUsers.length > 0 ? totalScore / activeUsers.length : 0;

// Return a single new item with the calculated average
return [{
  json: {
    averageActiveUserScore: averageScore,
    activeUserCount: activeUsers.length
  }
}];

Explanation: First, we filter for activeUsers. Then, reduce() is used to sum up their scores. Finally, we calculate the average, handling the case where there might be no active users to avoid division by zero. The result is returned as a single new item in an array.

Sample Output:

{
  "averageActiveUserScore": 88.8, // (85.5 + 92.1) / 2
  "activeUserCount": 2
}

4.4. Example 4: Generating Dynamic Data (UUID & Timestamp) ⏱️

Problem: Add a unique transactionId (UUID) and a createdAt timestamp to each item.

// A simple UUID generator function (not truly RFC4122 compliant but good enough for many cases)
const generateUUID = () => {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    const r = Math.random() * 16 | 0;
    const v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
};

return items.map(item => {
  return {
    json: {
      ...item.json,
      transactionId: generateUUID(),
      createdAt: new Date().toISOString() // ISO 8601 format
    }
  };
});

Explanation: We define a simple generateUUID function (you can find more robust ones online if needed). Then, for each item, we add a new transactionId and createdAt timestamp using new Date().toISOString() for a standardized format.

Sample Output (for first item):

{
  "id": 101,
  "firstName": "Alice",
  "lastName": "Smith",
  "email": "alice.smith@example.com",
  "age": 30,
  "role": "Admin",
  "isActive": true,
  "score": 85.5,
  "tags": ["marketing", "sales"],
  "transactionId": "b6f5d8e7-e9c1-4b3a-9f1d-2e8c7b6a5d4e", // Example UUID
  "createdAt": "2023-10-27T10:30:00.123Z" // Example timestamp
}

4.5. Example 5: Parsing Nested JSON Structures 🌳

Problem: Imagine tags was a string like "marketing,sales" instead of an array. Parse it into an actual array.

// Assuming original 'tags' was a string like "marketing,sales"
// If it's already an array, this example is slightly modified to demonstrate parsing
// For this example, let's assume `item.json.tags` is a string
return items.map(item => {
  const tagsString = item.json.tags;
  let parsedTags = [];

  if (typeof tagsString === 'string' && tagsString.trim() !== '') {
    parsedTags = tagsString.split(',').map(tag => tag.trim());
  } else if (Array.isArray(tagsString)) {
    // If it's already an array, just use it
    parsedTags = tagsString;
  }

  return {
    json: {
      ...item.json,
      tags: parsedTags
    }
  };
});

Explanation: This code checks if tags is a string. If it is, it splits the string by the comma , and uses map(tag => tag.trim()) to remove any leading/trailing whitespace from each tag. It also handles cases where tags might be an empty string or already an array.

Sample Output (for first item, assuming tags was “marketing,sales”):

{
  // ... other fields ...
  "tags": ["marketing", "sales"]
}

4.6. Example 6: Date & Time Calculations 🗓️

Problem: Calculate the user’s approximate birth year based on their age and the current year.

return items.map(item => {
  const age = item.json.age;
  const currentYear = new Date().getFullYear();
  let birthYear = null;

  if (typeof age === 'number' && age > 0) {
    birthYear = currentYear - age;
  }

  return {
    json: {
      ...item.json,
      approximateBirthYear: birthYear
    }
  };
});

Explanation: We get the current year using new Date().getFullYear(). Then, we subtract the user’s age to estimate their birth year. Basic validation ensures age is a valid positive number.

Sample Output (for first item, assuming current year 2023):

{
  // ... other fields ...
  "approximateBirthYear": 1993 // 2023 - 30
}

4.7. Example 7: Custom Looping & Iteration with Nested Data 🔄

Problem: For users with a “Admin” role, increase their score by 5 and add a new tag “vip”.

return items.map(item => {
  const isAdministrator = item.json.role === 'Admin';
  let newScore = item.json.score;
  let newTags = [...(item.json.tags || [])]; // Create a copy of tags array

  if (isAdministrator) {
    newScore = (newScore || 0) + 5;
    if (!newTags.includes('vip')) { // Add 'vip' tag only if not already present
      newTags.push('vip');
    }
  }

  return {
    json: {
      ...item.json,
      score: newScore,
      tags: newTags
    }
  };
});

Explanation: We iterate through each item. If the role is “Admin”, we update the score and add “vip” to the tags array. We use [...(item.json.tags || [])] to ensure newTags is always an array, even if tags was missing or null, and to create a copy so we don’t mutate the original array directly.

Sample Output (for first item):

{
  // ... other fields ...
  "score": 90.5, // 85.5 + 5
  "tags": ["marketing", "sales", "vip"]
}

4.8. Example 8: Error Handling & Fallback Values 🚧

Problem: If score or age is missing or invalid, set a default value instead of failing.

return items.map(item => {
  let score = item.json.score;
  let age = item.json.age;

  // Validate score: if not a number or less than 0, default to 50
  if (typeof score !== 'number' || score < 0) {
    console.warn(`Warning: Invalid score for item ID ${item.json.id}. Defaulting to 50.`);
    score = 50;
  }

  // Validate age: if not a number, less than 0, or greater than 120, default to 25
  if (typeof age !== 'number' || age  120) {
    console.warn(`Warning: Invalid age for item ID ${item.json.id}. Defaulting to 25.`);
    age = 25;
  }

  return {
    json: {
      ...item.json,
      score: score,
      age: age,
      dataValidationStatus: 'processed' // Add a status for auditing
    }
  };
});

Explanation: This example demonstrates robust data validation. It checks the type and range of score and age. If invalid, it logs a warning and assigns a default value. A dataValidationStatus field is added for traceability.

Sample Output (if Bob’s score was “abc” and age was -5):

// For Bob's item
{
  "id": 102,
  "firstName": "Bob",
  // ... other fields ...
  "score": 50, // Defaulted
  "age": 25,   // Defaulted
  "dataValidationStatus": "processed"
}

4.9. Example 9: Data Type Conversion ↔️

Problem: Convert the isActive boolean to a string (“Active”/”Inactive”) and score to an integer.

return items.map(item => {
  const isActiveBoolean = item.json.isActive;
  const scoreFloat = item.json.score;

  // Convert boolean to string
  const isActiveString = isActiveBoolean ? 'Active' : 'Inactive';

  // Convert float to integer (rounding down)
  const scoreInteger = Math.floor(scoreFloat || 0);

  return {
    json: {
      ...item.json,
      isActiveString: isActiveString,
      scoreInteger: scoreInteger
    }
  };
});

Explanation: We convert isActive from a boolean true/false to the strings “Active”/”Inactive” using a ternary operator. The score (which is a float) is converted to an integer using Math.floor(), effectively removing decimal places.

Sample Output (for first item):

{
  "id": 101,
  "firstName": "Alice",
  // ... other fields ...
  "isActive": true, // original
  "score": 85.5,    // original
  "isActiveString": "Active",
  "scoreInteger": 85
}

4.10. Example 10: Generating Custom Output Structure from Multiple Items 🏗️

Problem: Transform all input items into a single summary report, grouping users by their role.

const report = {
  summaryDate: new Date().toISOString(),
  totalUsers: items.length,
  usersByRole: {}
};

items.forEach(item => {
  const role = item.json.role || 'Unknown';
  const userSummary = {
    id: item.json.id,
    fullName: `${item.json.firstName} ${item.json.lastName}`,
    email: item.json.email,
    status: item.json.isActive ? 'Active' : 'Inactive'
  };

  if (!report.usersByRole[role]) {
    report.usersByRole[role] = [];
  }
  report.usersByRole[role].push(userSummary);
});

// Return a single item containing the entire report
return [{ json: report }];

Explanation: This advanced example demonstrates creating an entirely new, single output item based on aggregated and transformed data from multiple input items. We initialize a report object. Then, we iterate through items, categorize users by their role, and push simplified user summaries into the usersByRole object within the report. Finally, the entire report object is wrapped in an array and returned as a single item.

Sample Output (condensed):

[
  {
    "json": {
      "summaryDate": "2023-10-27T10:45:00.000Z",
      "totalUsers": 3,
      "usersByRole": {
        "Admin": [
          {
            "id": 101,
            "fullName": "Alice Smith",
            "email": "alice.smith@example.com",
            "status": "Active"
          },
          {
            "id": 103,
            "fullName": "Charlie Brown",
            "email": "charlie.b@example.com",
            "status": "Active"
          }
        ],
        "User": [
          {
            "id": 102,
            "fullName": "Bob Johnson",
            "email": "bob.j@example.com",
            "status": "Inactive"
          }
        ]
      }
    }
  }
]

Conclusion: Your Workflow, Your Rules! 🎉

The n8n Code Node is an incredibly powerful tool that breaks down the walls of what’s possible within your automation workflows. It transforms n8n from just a low-code/no-code platform into a highly adaptable environment where you can inject custom JavaScript logic exactly where and when you need it.

By understanding its core concepts (items, return, console.log) and applying best practices, you can confidently tackle complex data transformations, custom filtering, dynamic data generation, and sophisticated reporting.

Don’t be afraid to experiment! Start small, test frequently, and leverage console.log() to understand your data flow. With these 10 core examples as your foundation, you’re well on your way to truly conquering the n8n Code Node and building workflows that are as flexible and powerful as your imagination. Happy automating! 🚀✨

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다