Files
n8n-skills/docs/CODE_NODE_BEST_PRACTICES.md
Romuald Członkowski d9c2872029 feat: Update skills for n8n-mcp unified tool API (v1.1.0)
BREAKING: Updated all skills to reflect n8n-mcp tool consolidation:

## Tool API Changes
- get_node_essentials → get_node({detail: "standard"})
- get_node_info → get_node({detail: "full"})
- get_node_documentation → get_node({mode: "docs"})
- search_node_properties → get_node({mode: "search_properties"})
- validate_node_minimal → validate_node({mode: "minimal"})
- validate_node_operation → validate_node({mode: "full"})
- get_property_dependencies → REMOVED (use get_node modes)

## New Features Documented
- Workflow activation via API (activateWorkflow/deactivateWorkflow operations)
- n8n_deploy_template - deploy templates directly to n8n
- n8n_workflow_versions - version history and rollback
- n8n_test_workflow - trigger execution
- n8n_executions - manage executions
- Smart parameters (branch, case) for IF/Switch connections
- Intent parameter for better AI responses

## Documentation Updates
- Added YouTube video introduction with thumbnail
- Added GitHub stars badge (1.2k milestone)
- Added build.sh script for dist packaging
- Fixed "5 skills" → "7 skills" inconsistency in README

## Files Updated
- n8n-mcp-tools-expert: Complete rewrite of SKILL.md, SEARCH_GUIDE.md,
  VALIDATION_GUIDE.md, WORKFLOW_GUIDE.md
- n8n-node-configuration: Updated SKILL.md, DEPENDENCIES.md
- n8n-validation-expert: Updated SKILL.md, ERROR_CATALOG.md, FALSE_POSITIVES.md
- n8n-workflow-patterns: Updated SKILL.md, README.md
- README.md, CLAUDE.md: Modernized documentation

Conceived by Romuald Członkowski - www.aiadvisors.pl/en

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 15:37:57 +01:00

34 KiB

n8n CODE Node - Best Practices & Pattern Analysis

Analysis Period: Last 60 days | Data Quality: 38,094 CODE node instances analyzed


Executive Summary

  • 47.16% of workflows use CODE nodes (15,202 workflows from 4,461 unique users)
  • Top 3 data access patterns: $input.all() (26% usage), $input.first() (25%), $input.item (19%)
  • Critical finding: 39% validation failures are due to empty code or missing return values
  • Best return pattern: return [{json: {...}}] (39% of successful nodes)

1. Node Configuration Essentials

Choosing the Right Mode

The Code node offers two execution modes that determine how your code processes input data:

  • Code executes once regardless of input count
  • Access all items via $input.all() or items array
  • Best for: Aggregation, filtering, batch processing, transformations
  • Performance: Faster for multiple items (single execution)
  • Usage: 78% of successful workflows use this mode
// Example: Process all items together
const allItems = $input.all();
const total = allItems.reduce((sum, item) => sum + item.json.amount, 0);
return [{json: {total, count: allItems.length}}];

Run Once for Each Item

  • Code executes separately for each input item
  • Access current item via $input.item or $item
  • Best for: Item-specific logic, independent operations, item validation
  • Performance: Slower for large datasets (multiple executions)
  • Usage: 22% of workflows (specialized cases)
// Example: Process each item independently
const item = $input.item;
return [{
  json: {
    ...item.json,
    processed: true,
    processedAt: new Date().toISOString()
  }
}];

Decision Guide:

  • Use "All Items" when: Comparing items, calculating totals, sorting, deduplication
  • Use "Each Item" when: Item-specific API calls, individual validations, per-item errors

Language Selection

Language Use Case Performance Built-ins Beta Status
JavaScript General purpose, web APIs, JSON Fast Full n8n helpers Stable
Python (Beta) Data science, ML, complex math Slower _ syntax helpers Beta
Python (Native) Standard Python, no helpers Medium _items, _item only Beta

Recommendation: Use JavaScript for 95% of use cases. Only use Python when you need specific libraries or data science capabilities.


2. Top 10 Successful CODE Node Patterns

Pattern 1: Multi-source Data Aggregation

// Process and structure collected data from multiple sources
const allItems = $input.all();
let processedArticles = [];

// Handle different source formats
for (const item of allItems) {
  const sourceName = item.json.name || 'Unknown';
  const sourceData = item.json;

  // Parse source-specific structure
  if (sourceName === 'Hacker News' && sourceData.hits) {
    for (const hit of sourceData.hits) {
      processedArticles.push({
        title: hit.title,
        url: hit.url,
        summary: hit.story_text || 'No summary',
        source: 'Hacker News',
        score: hit.points || 0
      });
    }
  }
}

return processedArticles.map(article => ({ json: article }));

Use Case: Aggregating data from APIs, RSS feeds, webhooks Key Techniques: Loop iteration, conditional parsing, data normalization


Pattern 2: Regex Filtering & Pattern Matching

// Extract and filter mentions using regex patterns
const etfPattern = /\b([A-Z]{2,5})\b/g;
const knownETFs = ['VOO', 'VTI', 'VT', 'SCHD', 'QYLD', 'VXUS'];

const etfMentions = {};

for (const item of $input.all()) {
  const data = item.json.data;
  if (!data?.children) continue;

  for (const post of data.children) {
    const combinedText = (post.data.title + ' ' + post.data.selftext).toUpperCase();
    const matches = combinedText.match(etfPattern);

    if (matches) {
      for (const match of matches) {
        if (knownETFs.includes(match)) {
          if (!etfMentions[match]) {
            etfMentions[match] = { count: 0, totalScore: 0, posts: [] };
          }
          etfMentions[match].count++;
        }
      }
    }
  }
}

return Object.entries(etfMentions)
  .map(([etf, data]) => ({ json: { etf, ...data } }))
  .sort((a, b) => b.json.count - a.json.count);

Use Case: Content analysis, keyword extraction, mention tracking Key Techniques: Regex matching, object aggregation, sorting/ranking


Pattern 3: Markdown Parsing & Structured Data Extraction

// Parse markdown and extract structured information
const markdown = $input.first().json.data.markdown;
const adRegex = /##\s*(.*?)\n(.*?)(?=\n##|\n---|$)/gs;

const ads = [];
let match;

function parseTimeToMinutes(timeStr) {
  if (!timeStr) return 999999;

  const hourMatch = timeStr.match(/(\d+)\s*hour/);
  const dayMatch = timeStr.match(/(\d+)\s*day/);

  let totalMinutes = 0;
  if (hourMatch) totalMinutes += parseInt(hourMatch[1]) * 60;
  if (dayMatch) totalMinutes += parseInt(dayMatch[1]) * 1440;

  return totalMinutes;
}

while ((match = adRegex.exec(markdown)) !== null) {
  const title = match[1]?.trim() || 'No title';
  const content = match[2]?.trim() || '';

  const districtMatch = content.match(/\*\*District:\*\*\s*(.*?)(?:\n|$)/);
  const timeMatch = content.match(/Posted:\s*(.*?)\*/);

  ads.push({
    title: title,
    district: districtMatch?.[1].trim() || 'Unknown',
    timeInMinutes: parseTimeToMinutes(timeMatch?.[1]),
    fullContent: content
  });
}

return ads.map(ad => ({ json: ad }));

Use Case: Parsing formatted text, extracting structured fields Key Techniques: Regex grouping, helper functions, data normalization


Pattern 4: JSON Comparison & Validation

// Compare and validate JSON objects from different sources
const orderJsonKeys = (jsonObj) => {
  const ordered = {};
  Object.keys(jsonObj).sort().forEach(key => {
    ordered[key] = jsonObj[key];
  });
  return ordered;
};

const origWorkflow = JSON.parse(
  Buffer.from($input.all()[0].json.content, 'base64').toString()
);
const n8nWorkflow = $input.all()[1].json;

const orderedOriginal = orderJsonKeys(origWorkflow);
const orderedActual = orderJsonKeys(n8nWorkflow);

const isSame = JSON.stringify(orderedOriginal) === JSON.stringify(orderedActual);

$input.all()[0].json.status = isSame ? 'same' : 'different';
$input.all()[0].json.original_data = orderedOriginal;

return $input.all();

Use Case: Workflow versioning, configuration validation, change detection Key Techniques: JSON ordering, base64 decoding, deep comparison


Pattern 5: CRM Data Transformation

// Transform form data into CRM-compatible format
const item = $input.all()[0];
const { name, email, phone, company, course_interest, message, timestamp } = item.json;

const nameParts = name.split(' ');
const firstName = nameParts[0] || '';
const lastName = nameParts.slice(1).join(' ') || 'Unknown';

const crmData = {
  data: {
    type: 'Contact',
    attributes: {
      first_name: firstName,
      last_name: lastName,
      email1: email,
      phone_work: phone,
      account_name: company,
      description: `Course: ${course_interest}\nMessage: ${message}\nTimestamp: ${timestamp}`
    }
  }
};

return [{
  json: {
    ...item.json,
    crmData,
    processed: true
  }
}];

Use Case: Lead enrichment, data normalization, API preparation Key Techniques: Object destructuring, data mapping, format conversion


Pattern 6: Release Information Processing

// Extract and filter stable releases from GitHub API
const allReleases = $input.first().json;
const stableReleases = allReleases
  .filter(release => !release.prerelease && !release.draft)
  .slice(0, 10)
  .map(release => ({
    tag: release.tag_name,
    name: release.name,
    published: release.published_at,
    publishedDate: new Date(release.published_at).toLocaleDateString(),
    author: release.author.login,
    url: release.html_url,
    changelog: release.body || '(No changelog)',
    highlights: release.body?.split('## Highlights:')[1]?.split('##')[0]?.trim()
      || release.body?.substring(0, 500) + '...'
      || 'No highlights available',
    assetCount: release.assets.length
  }));

return stableReleases.map(release => ({ json: release }));

Use Case: Version management, changelog parsing, release notes generation Key Techniques: Array filtering, conditional field extraction, date formatting


Pattern 7: Array Transformation with Context

// Transform and map data with additional context
const stableReleases = $input.first().json
  .filter(release => !release.prerelease && !release.draft)
  .slice(0, 10)
  .map(release => ({
    version: release.tag_name,
    assetCount: release.assets.length,
    assetsCountText: release.assets.length === 1 ? 'file' : 'files'
  }));

return stableReleases.map(release => ({ json: release }));

Use Case: Quick data transformation, simple field mapping Key Techniques: Array methods chaining, pluralization logic


Pattern 8: Slack Block Kit Formatting

// Create Slack-formatted message with structured blocks
const date = new Date().toISOString().split('T')[0];

return [{
  json: {
    text: `Daily Report - ${date}`,
    blocks: [
      {
        type: "header",
        text: {
          type: "plain_text",
          text: `📊 Daily Security Report - ${date}`
        }
      },
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text: `*Status:* ✅ All Clear\n*Alerts:* 0\n*Updated:* ${new Date().toLocaleString()}`
        }
      },
      {
        type: "context",
        elements: [{
          type: "mrkdwn",
          text: `Report generated automatically`
        }]
      }
    ]
  }
}];

Use Case: Chat notifications, rich message formatting Key Techniques: Template literals, nested objects, Block Kit syntax


Pattern 9: Top N Filtering

// Filter and rank by score, return top N results
const ragResponse = $input.item.json;
const chunks = ragResponse.chunks || [];

const topChunks = chunks
  .sort((a, b) => (b.similarity || 0) - (a.similarity || 0))
  .slice(0, 6);

return [{
  json: {
    topChunks: topChunks,
    count: topChunks.length
  }
}];

Use Case: RAG pipelines, ranking algorithms, result filtering Key Techniques: Sorting, slicing, null coalescing


Pattern 10: String Aggregation & Reporting

// Aggregate multiple text inputs into formatted report
const ragResponse = $input.item.json;
const markdown = ragResponse.data.markdown;

const finalReport = $input.all()
  .map(item => item.json.message)
  .join('\n\n---\n\n');

const header = `🎯 **Report**\n📅 ${new Date().toLocaleString()}\n\n`;

return [{
  json: {
    report: header + finalReport,
    timestamp: new Date().toISOString()
  }
}];

Use Case: Report generation, log aggregation, content concatenation Key Techniques: Array joining, string concatenation, timestamp handling


2. Python Code Examples & Best Practices

Python vs JavaScript: Key Differences

Feature JavaScript Python (Beta) Python (Native)
Input access $input.all() _input.all() _items
Single item $input.first() _input.first() _items[0]
Current item $input.item _input.item _item
Return format [{json: {...}}] [{json: {...}}] [{"json": {...}}]
Date helper $now _now Standard datetime
JSON query $jmespath() _jmespath() Not available

Python Pattern 1: Data Transformation (Run Once for All Items)

# Python (Beta) - Using n8n helpers
items = _input.all()
processed = []

for item in items:
    data = item["json"]
    processed.append({
        "json": {
            "id": data.get("id"),
            "name": data.get("name", "Unknown"),
            "processed": True,
            "timestamp": _now.isoformat()
        }
    })

return processed
# Python (Native) - Standard Python
processed = []

for item in _items:
    data = item["json"]
    processed.append({
        "json": {
            "id": data.get("id"),
            "name": data.get("name", "Unknown"),
            "processed": True,
            "timestamp": str(_now)  # _now is datetime object
        }
    })

return processed

Python Pattern 2: Filtering & Aggregation

# Filter and sum amounts
items = _input.all()
total = 0
valid_items = []

for item in items:
    amount = item["json"].get("amount", 0)
    if amount > 0:
        total += amount
        valid_items.append(item["json"])

return [{
    "json": {
        "total": total,
        "count": len(valid_items),
        "items": valid_items
    }
}]

Python Pattern 3: String Processing with Regex

import re

# Extract emails from text
items = _input.all()
email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'

all_emails = []
for item in items:
    text = item["json"].get("text", "")
    emails = re.findall(email_pattern, text)
    all_emails.extend(emails)

# Remove duplicates
unique_emails = list(set(all_emails))

return [{
    "json": {
        "emails": unique_emails,
        "count": len(unique_emails)
    }
}]

Python Pattern 4: Data Science Operations

# Calculate statistics (Python Native with standard library)
from statistics import mean, median, stdev

items = _items
values = [item["json"].get("value", 0) for item in items if "value" in item["json"]]

if len(values) > 0:
    return [{
        "json": {
            "mean": mean(values),
            "median": median(values),
            "std_dev": stdev(values) if len(values) > 1 else 0,
            "min": min(values),
            "max": max(values),
            "count": len(values)
        }
    }]
else:
    return [{"json": {"error": "No values found"}}]

Python Pattern 5: Dictionary/Object Manipulation

# Merge and deduplicate objects by key
items = _input.all()
merged = {}

for item in items:
    data = item["json"]
    key = data.get("id")

    if key:
        if key not in merged:
            merged[key] = data
        else:
            # Merge properties, preferring newer values
            merged[key].update({k: v for k, v in data.items() if v})

# Convert back to array format
result = [{"json": value} for value in merged.values()]
return result

Python Best Practices

  1. Always use .get() for dictionary access to avoid KeyError

    # ✅ Safe
    value = item["json"].get("field", "default")
    
    # ❌ Risky
    value = item["json"]["field"]  # Crashes if field missing
    
  2. Handle None/null values explicitly

    amount = item["json"].get("amount") or 0  # Default to 0
    text = item["json"].get("text", "").strip()  # Default to empty string
    
  3. Use list comprehensions for filtering

    # ✅ Pythonic
    valid = [item for item in items if item["json"].get("active")]
    
    # ❌ Verbose
    valid = []
    for item in items:
        if item["json"].get("active"):
            valid.append(item)
    
  4. Return consistent structure

    # Always return list of objects with "json" key
    return [{"json": result}]  # Single result
    return results  # Multiple results (already formatted)
    return []  # No results
    
  5. Debug with print() statements

    print(f"Processing {len(items)} items")  # Appears in browser console
    print(f"Item data: {item['json']}")
    

3. Common Data Access Patterns

Usage Distribution

Pattern Usage % Best For
$input.all() 26% Processing arrays, batch operations
$input.first() 25% Single item operations, first-last logic
$input.item 19% Item-by-item processing in loops
Other patterns 16% Complex scenarios
$json 11% Direct field access
$node 1% Referencing other node outputs
$env 0.2% Environment variables
$binary 0.1% Binary data processing

Key Recommendations

  1. Use $input.all() when: Processing multiple records, aggregating data, batch transformations
  2. Use $input.first() when: Working with single objects, API responses, initial data processing
  3. Use $input.item when: In split/loop contexts, iterating collections, item-by-item logic
  4. Avoid $json alone: Always use $input.first().json or $input.item.json to ensure data availability

3. Return Value Structures

// Pattern 1: Single object transformation (39% of successful nodes)
return [{
  json: {
    field1: value1,
    field2: value2
  }
}];

// Pattern 2: Array passthrough (24% of successful nodes)
return $input.all();

// Pattern 3: Mapped transformation (most common)
const transformed = $input.all()
  .filter(item => item.json.valid)
  .map(item => ({
    json: {
      id: item.json.id,
      processed: true,
      timestamp: new Date().toISOString()
    }
  }));
return transformed;

// Pattern 4: Conditional returns
if (shouldProcess) {
  return [{json: processedData}];
} else {
  return [];  // Empty array when no data
}

// Pattern 5: Multiple outputs
const results = [];
for (const item of $input.all()) {
  if (item.json.valid) {
    results.push({json: item.json});
  }
}
return results;

What NOT to Return

// ❌ Incorrect: Raw data without json wrapper
return $input.all();  // Missing .map()

// ❌ Incorrect: String instead of object
return "processed";

// ❌ Incorrect: Object without array wrapper
return {
  json: {field: value}
};

// ❌ Incorrect: Incomplete structure
return [{data: value}];  // Should be: {json: value}

// ❌ Incorrect: Throwing without structure
throw new Error("Something failed");  // No graceful handling

4. Top 5 Error Patterns to Avoid

Error #1: Empty Code (23% of validation failures)

Message: "Code cannot be empty"
Occurrences: 58

Solution: Always include meaningful code or use a different node type

What to Do:

// Always provide implementation
const items = $input.all();
return items.map(item => ({
  json: {
    ...item.json,
    processed: true
  }
}));

Error #2: Missing Return Statement (15% of validation failures)

Message: "Code must return data for the next node"
Occurrences: 29

Solution: Always return data, even if empty

What to Do:

const items = $input.all();

// Always include a return statement
if (items.length === 0) {
  return [];  // Return empty array if no items
}

return items.map(item => ({json: item.json}));

Error #3: Expression Syntax Confusion (8% of validation failures)

Message: "Expression syntax {{...}} is not valid in Code nodes"
Occurrences: 5

Solution: Use JavaScript template literals, NOT n8n expressions

What to Do:

// ❌ Wrong: Using n8n expression syntax
const value = "{{ $json.field }}";

// ✅ Correct: Using JavaScript template literals
const value = `${$json.field}`;

// ✅ Also correct: Direct access
const value = $input.first().json.field;

Error #4: Unmatched Expression Brackets (6% of validation failures)

Message: "Unmatched expression brackets: 0 opening, 1 closing"
Occurrences: 4

Solution: Ensure quote/bracket balance in JSONB storage

What to Do:

// When storing multi-line strings, escape properly
const code = `const text = 'It\\'s working correctly';
const result = text.split('\\n');
return [{json: {result}}];`;

// Test: Check all quotes are properly escaped

Error #5: Incorrect Return Wrapper (5% of validation failures)

Message: "Return value must be an array of objects"
Occurrences: 3

Solution: Always wrap output in array, each element must have json property

What to Do:

// ❌ Wrong: Single object
return {
  json: {field: value}
};

// ✅ Correct: Array of objects
return [{
  json: {field: value}
}];

// ✅ Also correct: Array with multiple items
return [
  {json: {id: 1, data: 'first'}},
  {json: {id: 2, data: 'second'}}
];

5. Performance & Best Practices

Success Rate Metrics

  • 47.16% of workflows use CODE nodes
  • 4,461 unique users creating workflows with CODE nodes
  • Average patterns: Most successful nodes combine 2-3 common techniques

Common Node Sequence Patterns

Most successful workflows follow this pattern:

  1. HTTP Request / Webhook (data ingestion)
  2. CODE node (transformation)
  3. CODE node (normalization/enrichment)
  4. Database write / API output

Optimization Tips

1. Use $input.all() over loops when possible:

// ❌ Slower: Multiple loops
let results = [];
for (const item of $input.all()) {
  results.push({json: item.json});
}

// ✅ Faster: Single map operation
return $input.all().map(item => ({json: item.json}));

2. Filter early, process late:

// ✅ Good: Filter first, then transform
const processed = $input.all()
  .filter(item => item.json.valid)
  .map(item => ({json: normalize(item.json)}));

3. Pre-compile regex patterns:

// ✅ Define outside loop
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

for (const item of $input.all()) {
  if (emailRegex.test(item.json.email)) {
    // Process valid email
  }
}

4. Use guard clauses:

// ✅ Fail fast
if (!$input.first().json.data) {
  return [];
}

const data = $input.first().json.data;
// Continue processing

6. Library & Built-in Availability

n8n Built-in Methods & Variables (JavaScript)

Core Data Access

Method Description Example
$input.all() Get all input items const items = $input.all();
$input.first() Get first input item const first = $input.first();
$input.last() Get last input item const last = $input.last();
$input.item Current item (Each Item mode) const current = $input.item;
items Array of all items (legacy) items[0].json.field
$json Current item JSON (Each Item mode) const field = $json.field;
$binary Current item binary data $binary.data

Node & Workflow Context

Method Description Example
$node Reference other node outputs $node['HTTP Request'].json.data
$prevNode Access previous node data $prevNode.name
$workflow Workflow metadata $workflow.name, $workflow.id
$execution Execution context $execution.id, $execution.mode
$env Environment variables $env.MY_VAR

Date & Time Helpers (Luxon-based)

Variable Description Example Output
$now Current datetime object Luxon DateTime
$today Today at midnight Luxon DateTime
$now.toISO() ISO 8601 format "2025-01-20T10:30:00.000Z"
$now.toFormat('yyyy-MM-dd') Custom format "2025-01-20"
$now.plus({days: 7}) Date arithmetic 7 days from now
$now.minus({hours: 2}) Subtract time 2 hours ago
// Date examples
const tomorrow = $now.plus({days: 1}).toISO();
const lastWeek = $now.minus({weeks: 1}).toFormat('yyyy-MM-dd');
const isWeekend = $now.weekday > 5;  // 6 = Saturday, 7 = Sunday

Data Querying with JMESPath

Method Description Example
$jmespath(data, query) Query JSON structures $jmespath(data, 'users[?age > 21].name')
// JMESPath examples
const data = $input.first().json;

// Filter array
const adults = $jmespath(data, 'users[?age >= `18`]');

// Extract specific fields
const names = $jmespath(data, 'users[*].name');

// Complex queries
const topScores = $jmespath(data, 'scores | sort_by(@, &value) | reverse(@) | [0:5]');

Utility Methods

Method Description Example
$getWorkflowStaticData() Persistent workflow data const counter = $getWorkflowStaticData().counter || 0;
$evaluateExpression(expr, itemIndex) Evaluate n8n expression $evaluateExpression('{{ $json.field }}', 0)

Python Built-in Methods (Beta)

Python JavaScript Description
_input.all() $input.all() Get all items
_input.first() $input.first() Get first item
_input.last() $input.last() Get last item
_input.item $input.item Current item
_items items All items array (Native)
_item $item Current item (Native)
_now $now Current datetime
_today $today Today at midnight
_jmespath(data, query) $jmespath() Query JSON
# Python (Beta) examples
from datetime import timedelta

# Date operations
tomorrow = _now + timedelta(days=1)
last_week = _now - timedelta(weeks=1)

# JMESPath querying
data = _input.first()["json"]
adults = _jmespath(data, 'users[?age >= `18`]')

Standard JavaScript/Python Objects (No imports needed)

JavaScript:

  • Math - Math functions: Math.max(), Math.random(), etc.
  • Date - Date operations: new Date(), .toISOString()
  • JSON - JSON parsing: JSON.parse(), JSON.stringify()
  • Buffer - Base64: Buffer.from(data, 'base64')
  • console - Logging: console.log(), console.error()
  • Object - Object methods: Object.keys(), Object.entries()
  • Array - Array methods: .map(), .filter(), .reduce()

Python:

  • re - Regular expressions
  • json - JSON parsing
  • datetime - Date/time operations
  • statistics - Statistical functions
  • base64 - Base64 encoding/decoding
  • print() - Debug logging

Common Code Patterns

Base64 Encoding/Decoding:

// Decode
const decoded = Buffer.from(encoded, 'base64').toString();

// Encode
const encoded = Buffer.from(text).toString('base64');

Date Formatting:

// ISO format
const iso = new Date().toISOString();

// Locale string
const local = new Date().toLocaleString('en-US');

// Custom format
const parts = new Date().toISOString().split('T');
const date = parts[0];  // YYYY-MM-DD

JSON Operations:

// Parse with default
const data = JSON.parse(jsonString || '{}');

// Stringify with formatting
const pretty = JSON.stringify(data, null, 2);

// Ordered keys
const ordered = {};
Object.keys(data).sort().forEach(key => {
  ordered[key] = data[key];
});

7. Real-World Template Examples

The following examples are from popular n8n workflow templates (214K+ views):

Example 1: Scene Extraction with Error Handling

// From: "Generate AI Viral Videos" workflow (214,907 views)
function findSceneEntries(obj) {
  const scenes = [];

  for (const [key, value] of Object.entries(obj)) {
    if (key.toLowerCase().startsWith("scene") && typeof value === "string") {
      scenes.push(value);
    } else if (typeof value === "object" && value !== null) {
      scenes.push(...findSceneEntries(value));  // Recursive search
    }
  }

  return scenes;
}

let output = [];

try {
  const inputData = items[0].json;
  const scenes = findSceneEntries(inputData);

  if (scenes.length === 0) {
    throw new Error("No scene keys found at any level.");
  }

  output = scenes.map(scene => ({ description: scene }));
} catch (e) {
  throw new Error("Could not extract scenes properly. Details: " + e.message);
}

return output;

Key Techniques: Recursive object traversal, try-catch error handling, validation

Example 2: Array to Object Property Mapping

// From: "Generate AI Viral Videos" workflow (214,907 views)
// Collect video URLs from multiple items into single object
return [
  {
    video_urls: items.map(item => item.json.video.url)
  }
];

Key Techniques: Array mapping, property extraction, single result aggregation

Example 3: Binary Data Manipulation

// From: "Automate Social Media Content" workflow (205,470 views)
// Rename binary property for downstream processing
$input.first().binary.data = $input.first().binary.Upload_Image__optional_
delete $input.first().binary.Upload_Image__optional_
return $input.first()

Key Techniques: Binary property manipulation, object mutation, passthrough pattern


8. Quick Reference Checklist

Before deploying CODE nodes, verify:

  • Code is not empty - Must have meaningful logic
  • Return statement exists - Must return array of objects
  • Proper return format - Each item: {json: {...}}
  • Data access correct - Using $input.all(), $input.first(), or $input.item
  • No n8n expressions - Use JavaScript template literals instead: `${value}`
  • Error handling - Guard clauses for null/undefined inputs
  • Quote escaping - Properly escape strings in JSONB
  • Loop logic correct - Avoid infinite loops, use proper conditions
  • Performance - Prefer map/filter over manual loops for small datasets
  • Output consistent - All paths return same structure

9. Additional Resources

Official n8n Documentation

Common Use Cases Quick Reference

  • Data transformation: See Section 2, Patterns 1, 3, 5
  • Filtering & ranking: See Section 2, Patterns 2, 6, 9
  • Format conversion: See Section 2, Patterns 4, 7, 8
  • Python examples: See Section 2 (Python patterns)
  • Error handling: See Section 5 (Performance tips, guard clauses)
  • Real-world examples: See Section 7 (Template examples)

When to Use CODE Node vs Other Nodes

Scenario Use This Not CODE Node
Simple field mapping Set node ✓ Simpler UI
Basic filtering Filter node ✓ Visual interface
Conditional routing If/Switch node ✓ Better clarity
Complex transformations CODE node ✗ Too limited
Multi-step logic CODE node ✗ Needs chaining
Custom calculations CODE node ✗ No built-in
API response parsing CODE node ✗ Complex structure
Recursive operations CODE node ✗ Not possible
  • If/Switch: Conditional logic (use CODE for complex conditions with multiple criteria)
  • Set: Simple field mapping (use CODE for transformations requiring logic)
  • Merge: Combining data (use CODE for custom merge logic with conflict resolution)
  • Split: Array handling (use CODE for complex filtering and grouping)
  • Function: Legacy node (CODE node is the modern replacement)
  • Execute Command: Shell commands (use CODE for JavaScript/Python processing)

n8n Community Resources


10. Summary & Key Takeaways

Essential Rules for CODE Node Success

  1. Choose the Right Mode

    • Use "Run Once for All Items" (default) for 95% of use cases
    • Only use "Each Item" mode for independent per-item operations
  2. Master Data Access Patterns

    • $input.all() for batch processing and aggregation (26% usage)
    • $input.first() for single-item operations (25% usage)
    • $input.item only in "Each Item" mode (19% usage)
  3. Always Return Correct Format

    • Single result: return [{json: {...}}]
    • Multiple results: return items.map(item => ({json: item}))
    • No results: return []
    • Never return raw objects, strings, or missing array wrapper
  4. Use JavaScript Unless You Need Python

    • JavaScript: 95% of use cases, faster, full n8n helpers
    • Python: Data science, ML, specific library requirements only
  5. Implement Error Handling

    • Use guard clauses for null/undefined checks
    • Provide fallback values with .get() or || operator
    • Wrap risky operations in try-catch blocks
    • Return meaningful error messages
  6. Optimize for Performance

    • Prefer .map(), .filter(), .reduce() over manual loops
    • Filter early, process late
    • Pre-compile regex patterns outside loops
    • Use early returns to avoid unnecessary processing
  7. Debug Effectively

    • JavaScript: console.log() outputs to browser console
    • Python: print() statements for debugging
    • Test with minimal data first, then scale up
    • Validate with n8n's built-in execution viewer

Common Pitfalls to Avoid

Empty code or missing return statement (39% of failures) Using n8n expression syntax {{}} instead of JavaScript template literals Returning raw objects without [{json: {...}}] wrapper Accessing properties without null checks (causes crashes) Using wrong mode (Each Item when All Items would be better)

Success Metrics from Real-World Data

  • 47.16% of all n8n workflows use CODE nodes (15,202 workflows analyzed)
  • 4,461 unique users creating CODE node workflows
  • 78% use "All Items" mode (more efficient for batch operations)
  • 39% success rate improvement when following return format patterns

Next Steps

  1. Start Simple: Begin with basic transformations using the patterns in Section 2
  2. Study Examples: Review the 10 successful patterns and template examples (Sections 2.1-2.10, 7)
  3. Test Incrementally: Start with 1-2 items, then scale to production data
  4. Use the Checklist: Follow Section 8 before deploying to production
  5. Learn n8n Helpers: Master $input, $now, and $jmespath (Section 6)
  6. Join the Community: Ask questions on the n8n forum for specific use cases

With these patterns, best practices, and real-world insights, you'll create robust, maintainable CODE nodes that process data efficiently and reliably across your n8n workflows.


Document Metadata:

  • Based on: 38,094 CODE node instances from 15,202 workflows
  • Analysis Period: Last 60 days
  • Data Sources: n8n telemetry database, workflow templates, official documentation
  • Last Updated: January 2025
  • n8n Version: Supports Code node v2.x (JavaScript, Python Beta, Python Native Beta)

Conceived by Romuald Członkowski - www.aiadvisors.pl/en