n8n Code Node
đź’»
Transform Node

n8n Code Node

Master the n8n Code node for JavaScript and Python. Learn data access patterns, return structures, built-in methods, error handling, and real-world examples for custom automation logic.

The moment your visual workflow hits a wall, the Code node becomes your escape hatch. You need to calculate the difference between two dates in business days. Or transform a nested API response into a flat structure. Or aggregate hundreds of items into a single summary. The built-in nodes can’t help, but a few lines of code can.

The Code node is the most powerful and most misunderstood node in n8n. It lets you write JavaScript or Python directly inside your workflow, giving you unlimited transformation capabilities. But that power comes with responsibility: wrong return structures break workflows silently, type mismatches cause mysterious failures, and the difference between JavaScript and Python syntax trips up even experienced developers.

The Custom Logic Problem

n8n provides hundreds of pre-built nodes for common tasks. But automation requirements are infinite. No matter how many nodes exist, some transformation will always fall outside what visual configuration can handle.

Consider these scenarios that demand code:

  • Calculating a hash or checksum for data validation
  • Grouping items by multiple dynamic properties
  • Transforming deeply nested JSON into a different structure
  • Performing complex conditional logic across multiple fields
  • Aggregating data with custom business rules

The Edit Fields node handles simple mappings. The If node handles branching. But when you need algorithmic control over your data, the Code node is the answer.

What You’ll Learn

  • When to use the Code node versus simpler alternatives
  • The critical difference between JavaScript and Python modes
  • How the two run modes work and when to use each
  • The return structure rule that causes 90% of Code node errors
  • All built-in methods and variables for both languages
  • Common errors and exactly how to fix them
  • Debugging techniques that save hours of frustration
  • Real-world examples with both JavaScript and Python

When to Use the Code Node

Before writing any code, confirm the Code node is actually necessary. Overusing it creates maintenance burden and hides logic that could be visible in the workflow canvas.

ScenarioUse Code Node?Better Alternative
Simple field renamingNoEdit Fields node
Filter items by one conditionNoFilter node or If node
Format a single dateNoExpression with Luxon
Complex multi-field transformationYesCode gives full control
Aggregate all items into summaryYesReduce operations need code
Group items by dynamic propertyYesCode is the only option
Parse or generate custom formatsYesString manipulation needs code
Business logic with multiple conditionsYesCode is cleaner than nested Ifs
Sort by multiple criteriaDependsSort node handles simple cases
API response restructuringUsually yesCode handles nested data better

Rule of thumb: If you can accomplish the task with expressions in 1-2 nodes, skip the Code node. If you need loops, aggregations, or complex conditionals, the Code node is your tool.

For copy-paste JavaScript recipes covering common transformations, see our 25 JavaScript recipes for the Code node.

JavaScript vs Python: Choosing Your Language

The Code node supports both JavaScript and Python. Your choice affects performance, available features, and syntax patterns.

FactorJavaScriptPython
PerformanceFaster executionSlower (compilation overhead)
Syntax prefix$ (e.g., $input, $json)_ (e.g., _input, _item)
External modulesnpm packages (self-hosted)Limited support
Community examplesMore abundantGrowing rapidly
Date handlingLuxon built-inLuxon via _now
FamiliarityWeb developersData scientists, analysts
StabilityMatureStable since n8n v2

When to Choose JavaScript

  • You have JavaScript experience
  • Performance matters for large datasets
  • You need external npm packages
  • You want maximum community examples and support
  • Complex async operations (though Code node is synchronous)

When to Choose Python

  • You’re more comfortable with Python syntax
  • Your team uses Python elsewhere
  • The transformation logic is straightforward
  • You prefer Python’s cleaner syntax for data manipulation

Important: Python mode uses Pyodide to run Python in the browser. This adds compilation overhead, making Python noticeably slower than JavaScript for the same operation. For performance-critical workflows processing thousands of items, JavaScript is the better choice.

Code Node Fundamentals

Before diving into language specifics, understand the core concepts that apply to both JavaScript and Python.

Adding the Code Node

  1. Click + to add a node
  2. Search for “Code”
  3. Select the Code node
  4. Choose your language (JavaScript or Python)

The Two Run Modes

This single setting causes more confusion than anything else in the Code node.

ModeExecutionData AccessBest For
Run Once for All ItemsCode runs once, receives all items$input.all() / _input.all()Aggregations, batch processing, when items interact
Run Once for Each ItemCode runs separately per item$json / _itemSimple per-item transformations

Default is “Run Once for All Items.” Most transformations use this mode because it provides more control.

All Items mode example: You have 100 orders and need to calculate the total revenue. The code runs once, loops through all orders, and returns a single sum.

Each Item mode example: You have 100 orders and need to add a “processed” timestamp to each. The code runs 100 times, once per order, adding the timestamp individually.

The Golden Return Structure Rule

Every Code node must return data in a specific format. This rule causes the majority of Code node errors.

JavaScript:

return [
  {
    json: {
      // your data here
    }
  }
];

Python:

return [
  {
    "json": {
      # your data here
    }
  }
]

The structure is:

  1. An outer array containing items
  2. Each item is an object with a json property
  3. The json property contains your actual data

Forget this structure and your workflow breaks with cryptic errors like “Code doesn’t return items properly.”

JavaScript Deep Dive

JavaScript is the native language for n8n’s Code node, offering the best performance and most features.

Accessing Input Data

MethodReturnsUse Case
$input.all()Array of all itemsProcessing multiple items
$input.first()First item onlyWhen you need just one
$input.last()Last item onlyGetting the final item
$jsonCurrent item’s JSON (Each Item mode)Per-item transformations
$('NodeName').all()All items from specific nodeAccessing earlier node data
$('NodeName').first()First item from specific nodeGetting one item from a node

Example: All Items mode

// Get all incoming items as an array
const items = $input.all();

// Transform each item using map()
// map() creates a new array by applying a function to each element
return items.map(item => ({
  // Each returned object must have a 'json' wrapper
  json: {
    // Access original data via item.json.fieldName
    name: item.json.name,
    // Add new fields as needed
    processed: true
  }
}));

Example: Each Item mode

// In "Each Item" mode, $json gives direct access to current item's data
// No need to call $input.all() - the code runs once per item automatically
return [{
  json: {
    // Access fields directly from $json
    name: $json.name,
    processed: true
  }
}];

Referencing Other Nodes

Access data from any previous node using its exact name:

// Reference another node by its exact name (case-sensitive, include spaces)
// .all() returns an array of all items from that node
const httpData = $('HTTP Request').all();

// .first() returns only the first item
// .json accesses the actual data inside the item
const firstItem = $('HTTP Request').first().json;

// Chain together to get a specific field value
const userId = $('HTTP Request').first().json.userId;

Common mistake: The node name must match exactly, including spaces and capitalization. Copy the name from the node’s header bar to avoid typos.

Built-in Methods and Variables

n8n provides several built-in helpers:

Method/VariableDescriptionExample
$nowCurrent timestamp as Luxon DateTime$now.toFormat('yyyy-MM-dd')
$todayToday at midnight as Luxon DateTime$today.plus({ days: 7 })
$jmespath()Query JSON with JMESPath$jmespath(data, 'items[*].name')
$if()Conditional value$if(condition, trueVal, falseVal)
$executionCurrent execution metadata$execution.id
$workflowCurrent workflow metadata$workflow.name
$varsWorkflow variables$vars.apiKey
DateTimeLuxon DateTime classDateTime.now()

Date handling with Luxon:

// $now is a Luxon DateTime object representing the current moment
// toFormat() converts it to a string in your desired format
const today = $now.toFormat('yyyy-MM-dd'); // Output: "2025-12-16"

// plus() adds time to a date; returns a new DateTime object
// toISO() outputs in ISO 8601 format (great for APIs)
const nextWeek = $now.plus({ days: 7 }).toISO();

// DateTime.fromISO() parses an ISO date string into a DateTime object
// Then format it however you need
const parsed = DateTime.fromISO('2025-01-15').toFormat('MMMM d, yyyy'); // "January 15, 2025"

// diff() calculates the difference between two dates
// Second argument specifies the unit ('days', 'hours', 'months', etc.)
const start = DateTime.fromISO(item.json.startDate);
const end = DateTime.fromISO(item.json.endDate);
const days = end.diff(start, 'days').days; // Number of days between dates

External npm Modules

If you self-host n8n, you can enable external npm packages by setting an environment variable:

NODE_FUNCTION_ALLOW_EXTERNAL=lodash,axios,moment

Then in your Code node:

// Use require() to import external modules (NOT import/export syntax)
const _ = require('lodash');

// Now you can use lodash functions
// groupBy creates an object with keys from each item's 'category' field
const grouped = _.groupBy(items, 'category');

n8n Cloud users: External modules are restricted. Most transformations can be accomplished with built-in JavaScript methods.

See the official n8n Code node documentation for the complete list of allowed modules.

Error Handling

Wrap risky operations in try-catch to prevent workflow failures:

// Get all input items
const items = $input.all();

// Process each item, handling errors individually
return items.map(item => {
  try {
    // Code inside try block might throw an error
    // JSON.parse() fails if rawData isn't valid JSON
    const parsed = JSON.parse(item.json.rawData);

    // If successful, return the parsed data
    return {
      json: {
        success: true,
        data: parsed
      }
    };
  } catch (error) {
    // If an error occurs, this block runs instead
    // Log the error to browser console for debugging
    console.log('Parse error:', error.message);

    // Return an error object instead of crashing
    // This lets the workflow continue with other items
    return {
      json: {
        success: false,
        error: error.message,
        originalData: item.json.rawData  // Keep original for debugging
      }
    };
  }
});

This pattern lets the workflow continue even when individual items fail processing.

Python Deep Dive

Python mode brings familiar syntax for those who prefer it, with some important differences from JavaScript.

Syntax Differences

Python uses underscore prefix (_) instead of dollar sign ($):

JavaScriptPython
$input.all()_input.all()
$json_item
$now_now
$('Node').all()_("Node").all()

Accessing Input Data

All Items mode:

# Get all incoming items as a list
# Note: underscore prefix (_) instead of dollar sign ($)
items = _input.all()

# Build the result list manually
result = []

# Loop through each item
for item in items:
    # Append transformed data to result
    # Must use "json" key (as string) in Python
    result.append({
        "json": {
            # Access original fields via item.json.fieldName
            "name": item.json.name,
            # Python uses True/False (capitalized), not true/false
            "processed": True
        }
    })

# Return the complete result array
return result

Each Item mode:

# In "Each Item" mode, _item gives direct access to current item's data
# Code runs automatically for each item - no loop needed
return [{
    "json": {
        # Access fields directly from _item
        "name": _item.name,
        "processed": True
    }
}]

The JsProxy Challenge

When accessing n8n data in Python, you often encounter JsProxy objects instead of native Python types. This is because Python runs via Pyodide in the browser, and JavaScript objects aren’t automatically converted.

Symptom: Printing data shows [object Object] or operations fail unexpectedly.

Solution: Use .to_py() to convert JsProxy to Python dictionaries:

# Get all items from input
items = _input.all()

for item in items:
    # item.json is a JsProxy object (JavaScript object in Python)
    # JsProxy doesn't work with Python dict methods like .keys() or .get()

    # Convert JsProxy to native Python dictionary using .to_py()
    data = item.json.to_py()

    # Now 'data' is a regular Python dict - all Python methods work
    print(data)  # Shows actual data instead of [object Object]

When you need .to_py():

  • Iterating over object properties
  • Using Python dict methods
  • Serializing to JSON string
  • Any operation expecting a native Python type

Built-in Methods

Method/VariableDescription
_input.all()All items from input
_input.first()First item
_itemCurrent item (Each Item mode)
_("Node").all()Items from named node
_nowCurrent Luxon DateTime
_todayToday at midnight
_executionExecution metadata
_workflowWorkflow metadata

Debugging with print()

Use print() to output debug information to the browser console:

# Get all items
items = _input.all()

# Print how many items we're processing
# f-strings let you embed variables directly in strings
print(f"Processing {len(items)} items")

# enumerate() gives both index (i) and value (item) in each loop
for i, item in enumerate(items):
    # Convert to Python dict so we can see the actual contents
    data = item.json.to_py()
    # Print each item with its index number
    print(f"Item {i}: {data}")

Check the browser’s developer console (F12) to see output.

Python Limitations

Compared to JavaScript, Python mode has some restrictions:

  1. Slower performance: Pyodide compilation adds overhead
  2. Limited external packages: Fewer modules available than npm
  3. Async not supported: Code runs synchronously
  4. Some built-in methods differ: Check syntax carefully

For straightforward transformations, Python works excellently. For performance-critical or complex workflows, JavaScript may be preferable.

Common Errors and Fixes

These errors appear constantly in the n8n community forum. Here’s how to fix each one.

Error: “Code doesn’t return items properly”

Symptom: Workflow fails immediately after Code node executes.

Cause: Return value doesn’t match the required structure.

Wrong:

// Missing json wrapper
return [{ name: "test" }];

// Not an array
return { json: { name: "test" } };

// json points to array instead of object
return [{ json: ["item1", "item2"] }];

Correct:

return [{
  json: {
    name: "test"
  }
}];

Error: “Cannot read properties of undefined”

Symptom: Error mentions reading property of undefined.

Cause: Accessing a property on data that doesn’t exist.

Wrong:

// user might not exist
const email = item.json.user.email;

Correct:

// Optional chaining prevents error
const email = item.json.user?.email;

// Or with fallback
const email = item.json.user?.email ?? 'unknown';

Error: “SyntaxError: Cannot use import statement”

Symptom: Error when trying to use ES module imports.

Cause: Code node doesn’t support ES module syntax.

Wrong:

import lodash from 'lodash';

Correct:

const lodash = require('lodash');

Note: External modules require self-hosted n8n with proper configuration.

Error: Wrong data in subsequent nodes

Symptom: Next node receives unexpected data or [object Object].

Cause: Returning raw JavaScript objects without proper structure, or not converting JsProxy in Python.

JavaScript fix: Ensure you return [{ json: {...} }] format.

Python fix: Convert JsProxy objects with .to_py() before returning.

Common Error Reference Table

Error MessageLikely CauseFix
”Code doesn’t return items properly”Wrong return structureReturn [{ json: {...} }]
”Cannot read properties of undefined”Missing dataUse optional chaining ?.
”SyntaxError: Cannot use import”ES module syntaxUse require() instead
”items is not iterable”$input.all() returned undefinedCheck input connection
”[object Object]” in outputJsProxy not convertedUse .to_py() in Python
”Unexpected token”Syntax error in codeCheck for typos, missing brackets

Debugging Techniques

When Code nodes misbehave, these techniques help identify the problem quickly.

Console Logging

Add strategic log statements to trace data flow:

JavaScript:

// Start by logging what you received
const items = $input.all();
console.log('Input count:', items.length);

// JSON.stringify with (data, null, 2) formats output nicely
// 'null' means no filtering, '2' means 2-space indentation
console.log('First item:', JSON.stringify(items[0], null, 2));

// ... your transformation logic goes here ...

// Log output before returning to verify it's correct
console.log('Output:', JSON.stringify(result, null, 2));
return result;

Python:

# Log input data at the start
items = _input.all()
print(f"Input count: {len(items)}")

# Use .to_py() to see actual data instead of [object Object]
print(f"First item: {items[0].json.to_py()}")

# ... your transformation logic goes here ...

# Log final result before returning
print(f"Output: {result}")
return result

Check browser developer console (F12) to see output.

Pinned Data Testing

  1. Run your workflow once to get real data
  2. Click “Pin Data” on the node before Code
  3. Now test the Code node repeatedly with consistent input

This isolates the Code node from upstream variability.

Type Checking

When data behaves unexpectedly, check its type:

JavaScript:

// typeof returns: "string", "number", "boolean", "object", "undefined"
console.log('Type:', typeof item.json.value);

// Arrays also return "object" with typeof, so use Array.isArray()
console.log('Is array:', Array.isArray(item.json.items));

// Check if value exists before using it
console.log('Has value:', item.json.value !== undefined);

Python:

# type() shows the Python type of a variable
print(f"Type: {type(item.json)}")  # Likely shows JsProxy

# After conversion, shows actual Python type
data = item.json.to_py()
print(f"Type after to_py(): {type(data)}")  # Shows <class 'dict'>

Simplify and Rebuild

When stuck:

  1. Comment out most of your code
  2. Return simple static data to verify structure works
  3. Gradually add logic back, testing each addition

This isolates which specific line causes the problem.

For complex debugging scenarios, try our free workflow debugger tool.

Real-World Examples

Example 1: Aggregate Order Data

Scenario: Calculate total revenue and order count from order items.

JavaScript:

// Get all order items from input
const items = $input.all();

// reduce() processes an array and accumulates a single result
// First argument: callback function with (accumulator, currentItem)
// Second argument: initial value for accumulator
const summary = items.reduce((acc, item) => {
  // Add this order's amount to running total (use 0 if amount is missing)
  acc.totalRevenue += item.json.amount || 0;
  // Increment the order counter
  acc.orderCount += 1;
  // Must return accumulator for next iteration
  return acc;
}, { totalRevenue: 0, orderCount: 0 });  // Initial values

// Calculate average after the loop (avoid division by zero)
// toFixed(2) rounds to 2 decimal places and returns a string
summary.averageOrder = summary.orderCount > 0
  ? (summary.totalRevenue / summary.orderCount).toFixed(2)
  : 0;

// Return as a single item containing the summary
return [{
  json: summary
}];

Python:

# Get all order items
items = _input.all()

# Initialize counters
total_revenue = 0
order_count = 0

# Loop through each order
for item in items:
    # Convert JsProxy to Python dict for safe access
    data = item.json.to_py()
    # .get() returns the value or a default (0) if key doesn't exist
    total_revenue += data.get("amount", 0)
    order_count += 1

# Calculate average (ternary expression prevents division by zero)
average = round(total_revenue / order_count, 2) if order_count > 0 else 0

# Return single item with aggregated results
return [{
    "json": {
        "totalRevenue": total_revenue,
        "orderCount": order_count,
        "averageOrder": average
    }
}]

Example 2: Transform API Response

Scenario: Flatten nested user data from an API into a simple structure.

JavaScript:

// Get the API response (usually a single item with nested data)
const items = $input.all();
const apiResponse = items[0].json;

// Safely access nested array: data.users (use empty array as fallback)
// Optional chaining (?.) prevents errors if 'data' doesn't exist
const users = (apiResponse.data?.users || []).map(user => ({
  // Each user becomes a separate n8n item
  json: {
    id: user.id,
    // Template literal combines first and last name; trim() removes extra spaces
    fullName: `${user.firstName} ${user.lastName}`.trim(),
    // Chain optional access for deeply nested properties
    email: user.contact?.email?.toLowerCase(),
    // Use null as explicit "no value" indicator
    phone: user.contact?.phone || null,
    // Parse ISO date and reformat to simple date string
    createdAt: DateTime.fromISO(user.createdAt).toFormat('yyyy-MM-dd')
  }
}));

// Return array of user items (one item per user)
return users;

Python:

# Get the API response
items = _input.all()
# Must convert to Python dict to use .get() method
api_response = items[0].json.to_py()

# Safely navigate nested structure with .get() and default values
# .get("key", default) returns default if key doesn't exist
users = api_response.get("data", {}).get("users", [])
result = []

for user in users:
    result.append({
        "json": {
            "id": user.get("id"),
            # f-string combines names; .strip() removes leading/trailing whitespace
            "fullName": f"{user.get('firstName', '')} {user.get('lastName', '')}".strip(),
            # Conditional expression handles missing 'contact' object
            "email": user.get("contact", {}).get("email", "").lower() if user.get("contact") else None,
            "phone": user.get("contact", {}).get("phone"),
            # Slice string to get first 10 characters (YYYY-MM-DD)
            "createdAt": user.get("createdAt", "")[:10]
        }
    })

return result

Example 3: Group and Count Items

Scenario: Group products by category and count items per category.

JavaScript:

// Get all product items
const items = $input.all();

// Use reduce() to build a grouped object
// Start with empty object {} as initial accumulator
const grouped = items.reduce((acc, item) => {
  // Get category (or default to 'Uncategorized')
  const category = item.json.category || 'Uncategorized';

  // If this category doesn't exist yet, create it
  if (!acc[category]) {
    acc[category] = { count: 0, items: [] };
  }

  // Increment count and add product name to list
  acc[category].count += 1;
  acc[category].items.push(item.json.name);

  return acc;
}, {});  // Initial value: empty object

// Return summary with all categories and their data
return [{
  json: {
    // Object.keys() returns array of all category names
    categories: Object.keys(grouped),
    // The full grouped data structure
    breakdown: grouped,
    // Total number of unique categories
    totalCategories: Object.keys(grouped).length
  }
}];

Python:

# Get all product items
items = _input.all()

# Initialize empty dictionary for grouping
grouped = {}

for item in items:
    # Convert JsProxy to Python dict
    data = item.json.to_py()
    # Get category with fallback to "Uncategorized"
    category = data.get("category", "Uncategorized")

    # Create category entry if it doesn't exist
    if category not in grouped:
        grouped[category] = {"count": 0, "items": []}

    # Increment count and add product name
    grouped[category]["count"] += 1
    grouped[category]["items"].append(data.get("name"))

# Return summary with category breakdown
return [{
    "json": {
        # list() converts dict_keys to a regular list
        "categories": list(grouped.keys()),
        # The full grouped data structure
        "breakdown": grouped,
        # len() counts unique categories
        "totalCategories": len(grouped)
    }
}]

For 25 additional JavaScript recipes covering dates, strings, arrays, and API responses, see our complete JavaScript Code node recipe guide.

Pro Tips and Best Practices

1. Start with Expressions

Before reaching for the Code node, check if n8n expressions can handle your transformation. Expressions work in any node field and handle many common cases without code.

2. Name Your Code Nodes

Instead of “Code” or “Code1”, use descriptive names:

  • “Calculate Order Totals”
  • “Transform API Response”
  • “Group By Category”

This makes workflows self-documenting.

3. Keep Code Focused

Each Code node should do one thing well. If your code exceeds 50 lines, consider:

  • Breaking into multiple Code nodes
  • Using a sub-workflow
  • Whether a different approach is cleaner

4. Handle Empty Inputs

Check for empty input before processing:

// Always get input items first
const items = $input.all();

// Check if array is empty before processing
// This prevents errors when looping over empty arrays
if (items.length === 0) {
  // Return a message item instead of crashing
  return [{ json: { message: 'No items to process' } }];
}

// Safe to continue - we know items exist
// ... your processing logic here ...

5. Validate Before Transform

When data comes from external sources, validate it:

// Get all input items
const items = $input.all();

return items.map(item => {
  // Extract the value to validate
  const email = item.json.email;

  // Simple validation: email exists AND contains '@'
  // Returns true or false
  const isValidEmail = email && email.includes('@');

  return {
    json: {
      // Spread operator (...) copies all original fields
      ...item.json,
      // Add validation result as new field
      emailValid: isValidEmail,
      // Add timestamp for when this was processed
      processedAt: $now.toISO()
    }
  };
});

6. Test with Edge Cases

Before deploying, test your Code node with:

  • Empty arrays
  • Null values
  • Missing fields
  • Unexpected data types
  • Very large datasets

Our expression validator tool helps test expressions, and the JSON fixer tool helps with malformed JSON.

For production workflows requiring robust error handling and complex transformations, our workflow development services can help design maintainable solutions. For architectural guidance, explore our n8n consulting services.

Frequently Asked Questions

Can I make HTTP requests from the Code node?

No, the Code node runs synchronously and cannot make external HTTP requests directly. Use the HTTP Request node for API calls, then process the response in a subsequent Code node if needed. This separation keeps your workflow visible and debuggable. The Code node is designed for data transformation, not external communication.

Why is my Python Code node so slow compared to JavaScript?

Python in n8n runs via Pyodide, which compiles Python to WebAssembly. This compilation step adds significant overhead, especially on first execution. JavaScript runs natively and is substantially faster. For workflows processing thousands of items or running frequently, JavaScript is the better choice. Python mode is ideal when familiarity matters more than raw performance, or for simpler transformations where the speed difference is negligible.

How do I return multiple items from a single input item?

Return an array with multiple objects, each wrapped in the required structure. For example, to split one order into its line items:

// Get all order items
const items = $input.all();

// This array will hold all the line items we extract
const allLineItems = [];

// Loop through each order
for (const item of items) {
  // Loop through line items within this order (use empty array if none exist)
  for (const lineItem of item.json.lineItems || []) {
    // Create a new n8n item for each line item
    allLineItems.push({
      json: {
        // Include the parent order ID for reference
        orderId: item.json.orderId,
        // Spread all line item properties into this object
        ...lineItem
      }
    });
  }
}

// Return all extracted line items
// If one order has 5 line items, this returns 5 separate n8n items
return allLineItems;

Each object in the returned array becomes a separate item in the workflow.

What’s the difference between $json and $input.first().json?

In “Run Once for Each Item” mode, $json refers to the current item being processed. In “Run Once for All Items” mode, $json is not available because no single “current item” exists. Use $input.first().json when you specifically need the first item’s data in All Items mode, or $input.all() to get every item. The key is understanding which mode your Code node uses and accessing data accordingly.

How can I access environment variables in the Code node?

Use $env to access environment variables configured in your n8n instance:

// Access environment variables using $env.VARIABLE_NAME
// These are set in your n8n instance configuration, not in the workflow
const apiEndpoint = $env.API_ENDPOINT;

// Environment variables are always strings
// Compare to string 'true' to get boolean behavior
const debugMode = $env.DEBUG_MODE === 'true';

// Use in your logic
if (debugMode) {
  console.log('Debug mode enabled, calling:', apiEndpoint);
}

For self-hosted n8n, set these in your environment or .env file. For n8n Cloud, configure them in your instance settings. Never hardcode sensitive values like API keys in the Code node itself. Use n8n’s credentials system or environment variables to keep secrets secure. See our workflow best practices guide for more on credential management.

Ready to Automate Your Business?

Tell us what you need automated. We'll build it, test it, and deploy it fast.

âś“ 48-72 Hour Turnaround
âś“ Production Ready
âś“ Free Consultation
⚡

Create Your Free Account

Sign up once, use all tools free forever. We require accounts to prevent abuse and keep our tools running for everyone.

or

By signing up, you agree to our Terms of Service and Privacy Policy. No spam, unsubscribe anytime.