Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    czlonkowski

    n8n-code-javascript

    czlonkowski/n8n-code-javascript
    Coding
    2,613
    2 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Write JavaScript code in n8n Code nodes...

    SKILL.md

    JavaScript Code Node

    Expert guidance for writing JavaScript code in n8n Code nodes.


    Quick Start

    // Basic template for Code nodes
    const items = $input.all();
    
    // Process data
    const processed = items.map(item => ({
      json: {
        ...item.json,
        processed: true,
        timestamp: new Date().toISOString()
      }
    }));
    
    return processed;
    

    Essential Rules

    1. Choose "Run Once for All Items" mode (recommended for most use cases)
    2. Access data: $input.all(), $input.first(), or $input.item
    3. CRITICAL: Must return [{json: {...}}] format
    4. CRITICAL: Webhook data is under $json.body (not $json directly)
    5. Built-ins available: $helpers.httpRequest() (no auth), DateTime (Luxon), $jmespath(). Not available: $helpers.httpRequestWithAuthentication, $env (when N8N_BLOCK_ENV_ACCESS_IN_NODE=true), require() (unless allowlisted)

    Mode Selection Guide

    The Code node offers two execution modes. Choose based on your use case:

    Run Once for All Items (Recommended - Default)

    Use this mode for: 95% of use cases

    • How it works: Code executes once regardless of input count
    • Data access: $input.all() or items array
    • Best for: Aggregation, filtering, batch processing, transformations, API calls with all data
    • Performance: Faster for multiple items (single execution)
    // Example: Calculate total from all items
    const allItems = $input.all();
    const total = allItems.reduce((sum, item) => sum + (item.json.amount || 0), 0);
    
    return [{
      json: {
        total,
        count: allItems.length,
        average: total / allItems.length
      }
    }];
    

    When to use:

    • ✅ Comparing items across the dataset
    • ✅ Calculating totals, averages, or statistics
    • ✅ Sorting or ranking items
    • ✅ Deduplication
    • ✅ Building aggregated reports
    • ✅ Combining data from multiple items

    Run Once for Each Item

    Use this mode for: Specialized cases only

    • How it works: Code executes separately for each input item
    • Data access: $input.item or $item
    • Best for: Item-specific logic, independent operations, per-item validation
    • Performance: Slower for large datasets (multiple executions)
    // Example: Add processing timestamp to each item
    const item = $input.item;
    
    return [{
      json: {
        ...item.json,
        processed: true,
        processedAt: new Date().toISOString()
      }
    }];
    

    When to use:

    • ✅ Each item needs independent API call
    • ✅ Per-item validation with different error handling
    • ✅ Item-specific transformations based on item properties
    • ✅ When items must be processed separately for business logic

    Decision Shortcut:

    • Need to look at multiple items? → Use "All Items" mode
    • Each item completely independent? → Use "Each Item" mode
    • Not sure? → Use "All Items" mode (you can always loop inside)

    Data Access Patterns

    Pattern 1: $input.all() - Most Common

    Use when: Processing arrays, batch operations, aggregations

    // Get all items from previous node
    const allItems = $input.all();
    
    // Filter, map, reduce as needed
    const valid = allItems.filter(item => item.json.status === 'active');
    const mapped = valid.map(item => ({
      json: {
        id: item.json.id,
        name: item.json.name
      }
    }));
    
    return mapped;
    

    Pattern 2: $input.first() - Very Common

    Use when: Working with single objects, API responses, first-in-first-out

    // Get first item only
    const firstItem = $input.first();
    const data = firstItem.json;
    
    return [{
      json: {
        result: processData(data),
        processedAt: new Date().toISOString()
      }
    }];
    

    Pattern 3: $input.item - Each Item Mode Only

    Use when: In "Run Once for Each Item" mode

    // Current item in loop (Each Item mode only)
    const currentItem = $input.item;
    
    return [{
      json: {
        ...currentItem.json,
        itemProcessed: true
      }
    }];
    

    Pattern 4: $node - Reference Other Nodes

    Use when: Need data from specific nodes in workflow

    // Get output from specific node
    const webhookData = $node["Webhook"].json;
    const httpData = $node["HTTP Request"].json;
    
    return [{
      json: {
        combined: {
          webhook: webhookData,
          api: httpData
        }
      }
    }];
    

    See: DATA_ACCESS.md for comprehensive guide


    Critical: Webhook Data Structure

    MOST COMMON MISTAKE: Webhook data is nested under .body

    // ❌ WRONG - Will return undefined
    const name = $json.name;
    const email = $json.email;
    
    // ✅ CORRECT - Webhook data is under .body
    const name = $json.body.name;
    const email = $json.body.email;
    
    // Or with $input
    const webhookData = $input.first().json.body;
    const name = webhookData.name;
    

    Why: Webhook node wraps all request data under body property. This includes POST data, query parameters, and JSON payloads.

    See: DATA_ACCESS.md for full webhook structure details


    Return Format Requirements

    CRITICAL RULE: Always return array of objects with json property

    Correct Return Formats

    // ✅ Single result
    return [{
      json: {
        field1: value1,
        field2: value2
      }
    }];
    
    // ✅ Multiple results
    return [
      {json: {id: 1, data: 'first'}},
      {json: {id: 2, data: 'second'}}
    ];
    
    // ✅ Transformed array
    const transformed = $input.all()
      .filter(item => item.json.valid)
      .map(item => ({
        json: {
          id: item.json.id,
          processed: true
        }
      }));
    return transformed;
    
    // ✅ Empty result (when no data to return)
    return [];
    
    // ✅ Conditional return
    if (shouldProcess) {
      return [{json: processedData}];
    } else {
      return [];
    }
    

    Incorrect Return Formats

    // ❌ WRONG: Object without array wrapper
    return {
      json: {field: value}
    };
    
    // ❌ WRONG: Array without json wrapper
    return [{field: value}];
    
    // ❌ WRONG: Plain string
    return "processed";
    
    // ❌ WRONG: Raw data without mapping
    return $input.all();  // Missing .map()
    
    // ❌ WRONG: Incomplete structure
    return [{data: value}];  // Should be {json: value}
    

    Why it matters: Next nodes expect array format. Incorrect format causes workflow execution to fail.

    See: ERROR_PATTERNS.md #3 for detailed error solutions


    Common Patterns Overview

    Based on production workflows, here are the most useful patterns:

    1. Multi-Source Data Aggregation

    Combine data from multiple APIs, webhooks, or nodes

    const allItems = $input.all();
    const results = [];
    
    for (const item of allItems) {
      const sourceName = item.json.name || 'Unknown';
      // Parse source-specific structure
      if (sourceName === 'API1' && item.json.data) {
        results.push({
          json: {
            title: item.json.data.title,
            source: 'API1'
          }
        });
      }
    }
    
    return results;
    

    2. Filtering with Regex

    Extract patterns, mentions, or keywords from text

    const pattern = /\b([A-Z]{2,5})\b/g;
    const matches = {};
    
    for (const item of $input.all()) {
      const text = item.json.text;
      const found = text.match(pattern);
    
      if (found) {
        found.forEach(match => {
          matches[match] = (matches[match] || 0) + 1;
        });
      }
    }
    
    return [{json: {matches}}];
    

    3. Data Transformation & Enrichment

    Map fields, normalize formats, add computed fields

    const items = $input.all();
    
    return items.map(item => {
      const data = item.json;
      const nameParts = data.name.split(' ');
    
      return {
        json: {
          first_name: nameParts[0],
          last_name: nameParts.slice(1).join(' '),
          email: data.email,
          created_at: new Date().toISOString()
        }
      };
    });
    

    4. Top N Filtering & Ranking

    Sort and limit results

    const items = $input.all();
    
    const topItems = items
      .sort((a, b) => (b.json.score || 0) - (a.json.score || 0))
      .slice(0, 10);
    
    return topItems.map(item => ({json: item.json}));
    

    5. Aggregation & Reporting

    Sum, count, group data

    const items = $input.all();
    const total = items.reduce((sum, item) => sum + (item.json.amount || 0), 0);
    
    return [{
      json: {
        total,
        count: items.length,
        average: total / items.length,
        timestamp: new Date().toISOString()
      }
    }];
    

    See: COMMON_PATTERNS.md for 10 detailed production patterns


    Error Prevention - Top 5 Mistakes

    #1: Empty Code or Missing Return (Most Common)

    // ❌ WRONG: No return statement
    const items = $input.all();
    // ... processing code ...
    // Forgot to return!
    
    // ✅ CORRECT: Always return data
    const items = $input.all();
    // ... processing ...
    return items.map(item => ({json: item.json}));
    

    #2: Expression Syntax Confusion

    // ❌ WRONG: Using n8n expression syntax in code
    const value = "{{ $json.field }}";
    
    // ✅ CORRECT: Use JavaScript template literals
    const value = `${$json.field}`;
    
    // ✅ CORRECT: Direct access
    const value = $input.first().json.field;
    

    #3: Incorrect Return Wrapper

    // ❌ WRONG: Returning object instead of array
    return {json: {result: 'success'}};
    
    // ✅ CORRECT: Array wrapper required
    return [{json: {result: 'success'}}];
    

    #4: Missing Null Checks

    // ❌ WRONG: Crashes if field doesn't exist
    const value = item.json.user.email;
    
    // ✅ CORRECT: Safe access with optional chaining
    const value = item.json?.user?.email || 'no-email@example.com';
    
    // ✅ CORRECT: Guard clause
    if (!item.json.user) {
      return [];
    }
    const value = item.json.user.email;
    

    #5: Webhook Body Nesting

    // ❌ WRONG: Direct access to webhook data
    const email = $json.email;
    
    // ✅ CORRECT: Webhook data under .body
    const email = $json.body.email;
    

    See: ERROR_PATTERNS.md for comprehensive error guide


    Built-in Functions & Helpers

    $helpers.httpRequest()

    Make HTTP requests from within code:

    const response = await $helpers.httpRequest({
      method: 'GET',
      url: 'https://api.example.com/data',
      headers: {
        'Authorization': 'Bearer token',
        'Content-Type': 'application/json'
      }
    });
    
    return [{json: {data: response}}];
    

    DateTime (Luxon)

    Date and time operations:

    // Current time
    const now = DateTime.now();
    
    // Format dates
    const formatted = now.toFormat('yyyy-MM-dd');
    const iso = now.toISO();
    
    // Date arithmetic
    const tomorrow = now.plus({days: 1});
    const lastWeek = now.minus({weeks: 1});
    
    return [{
      json: {
        today: formatted,
        tomorrow: tomorrow.toFormat('yyyy-MM-dd')
      }
    }];
    

    $jmespath()

    Query JSON structures:

    const data = $input.first().json;
    
    // Filter array
    const adults = $jmespath(data, 'users[?age >= `18`]');
    
    // Extract fields
    const names = $jmespath(data, 'users[*].name');
    
    return [{json: {adults, names}}];
    

    See: BUILTIN_FUNCTIONS.md for complete reference


    Best Practices

    1. Always Validate Input Data

    const items = $input.all();
    
    // Check if data exists
    if (!items || items.length === 0) {
      return [];
    }
    
    // Validate structure
    if (!items[0].json) {
      return [{json: {error: 'Invalid input format'}}];
    }
    
    // Continue processing...
    

    2. Use Try-Catch for Error Handling

    try {
      const response = await $helpers.httpRequest({
        url: 'https://api.example.com/data'
      });
    
      return [{json: {success: true, data: response}}];
    } catch (error) {
      return [{
        json: {
          success: false,
          error: error.message
        }
      }];
    }
    

    3. Prefer Array Methods Over Loops

    // ✅ GOOD: Functional approach
    const processed = $input.all()
      .filter(item => item.json.valid)
      .map(item => ({json: {id: item.json.id}}));
    
    // ❌ SLOWER: Manual loop
    const processed = [];
    for (const item of $input.all()) {
      if (item.json.valid) {
        processed.push({json: {id: item.json.id}});
      }
    }
    

    4. Filter Early, Process Late

    // ✅ GOOD: Filter first to reduce processing
    const processed = $input.all()
      .filter(item => item.json.status === 'active')  // Reduce dataset first
      .map(item => expensiveTransformation(item));  // Then transform
    
    // ❌ WASTEFUL: Transform everything, then filter
    const processed = $input.all()
      .map(item => expensiveTransformation(item))  // Wastes CPU
      .filter(item => item.json.status === 'active');
    

    5. Use Descriptive Variable Names

    // ✅ GOOD: Clear intent
    const activeUsers = $input.all().filter(item => item.json.active);
    const totalRevenue = activeUsers.reduce((sum, user) => sum + user.json.revenue, 0);
    
    // ❌ BAD: Unclear purpose
    const a = $input.all().filter(item => item.json.active);
    const t = a.reduce((s, u) => s + u.json.revenue, 0);
    

    6. Debug with console.log()

    // Debug statements appear in browser console
    const items = $input.all();
    console.log(`Processing ${items.length} items`);
    
    for (const item of items) {
      console.log('Item data:', item.json);
      // Process...
    }
    
    return result;
    

    Production Gotchas

    Hard-won lessons from real-world n8n workflow deployments:

    SplitInBatches Loop Semantics

    The SplitInBatches node has two outputs — and the naming is counterintuitive:

    • main[0] = done — fires ONCE after all batches are processed
    • main[1] = each batch — fires for every batch (this is the loop body)

    Always add a Limit 1 node after the done output before downstream processing, as a safety against edge cases where done fires with extra items.

    Cross-Iteration Data Accumulation (CRITICAL)

    After a SplitInBatches loop, $('Node Inside Loop').all() returns ONLY the last iteration's items, not cumulative results. This silently drops data from all but the final batch.

    Fix: Use workflow static data to accumulate across iterations:

    // BEFORE the loop (reset accumulator):
    const staticData = $getWorkflowStaticData('global');
    staticData.results = [];
    return $input.all();
    
    // INSIDE the loop body (accumulate):
    const staticData = $getWorkflowStaticData('global');
    const results = [];
    for (const item of $input.all()) {
      const processed = { /* ... */ };
      results.push({ json: processed });
      staticData.results.push(processed);
    }
    return results;
    
    // AFTER the loop (read accumulated data):
    const staticData = $getWorkflowStaticData('global');
    const allResults = staticData.results || [];
    // Now aggregate across ALL iterations
    

    pairedItem for New Output Items

    When creating new items that don't map 1:1 to input items, include pairedItem — otherwise downstream Set nodes fail with paired_item_no_info:

    const results = [];
    for (let i = 0; i < $input.all().length; i++) {
      const item = $input.all()[i];
      results.push({
        json: { /* new data */ },
        pairedItem: { item: i }
      });
    }
    return results;
    

    Correct Node Reference Syntax

    // ❌ WRONG - .json directly on node reference
    const data = $('HTTP Request').json;
    
    // ✅ CORRECT - call .first() then access .json
    const data = $('HTTP Request').first().json;
    
    // ✅ Also correct - get all items
    const allData = $('HTTP Request').all();
    

    Float Precision for Price/Currency Comparison

    When comparing prices or currency values, floating point noise can cause false positives. Round to cents:

    // ❌ Unreliable - float comparison
    if (newPrice !== oldPrice) { /* triggers on noise */ }
    
    // ✅ Reliable - compare at cent level
    if (Math.round(newPrice * 100) !== Math.round(oldPrice * 100)) {
      // Real price change detected
    }
    

    When to Use Code Node

    Use Code node when:

    • ✅ Complex transformations requiring multiple steps
    • ✅ Custom calculations or business logic
    • ✅ Recursive operations
    • ✅ API response parsing with complex structure
    • ✅ Multi-step conditionals
    • ✅ Data aggregation across items

    Consider other nodes when:

    • ❌ Simple field mapping → Use Set node
    • ❌ Basic filtering → Use Filter node
    • ❌ Simple conditionals → Use IF or Switch node
    • ❌ HTTP requests only → Use HTTP Request node

    Code node excels at: Complex logic that would require chaining many simple nodes


    Integration with Other Skills

    Works With:

    n8n Expression Syntax:

    • Expressions use {{ }} syntax in other nodes
    • Code nodes use JavaScript directly (no {{ }})
    • When to use expressions vs code

    n8n MCP Tools Expert:

    • How to find Code node: search_nodes({query: "code"})
    • Get configuration help: get_node({nodeType: "nodes-base.code"})
    • Validate code: validate_node({nodeType: "nodes-base.code", config: {...}})

    n8n Node Configuration:

    • Mode selection (All Items vs Each Item)
    • Language selection (JavaScript vs Python)
    • Understanding property dependencies

    n8n Workflow Patterns:

    • Code nodes in transformation step
    • Webhook → Code → API pattern
    • Error handling in workflows

    n8n Validation Expert:

    • Validate Code node configuration
    • Handle validation errors
    • Auto-fix common issues

    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: `${value}`
    • Error handling - Guard clauses for null/undefined inputs
    • Webhook data - Access via .body if from webhook
    • Mode selection - "All Items" for most cases
    • Performance - Prefer map/filter over manual loops
    • Output consistent - All code paths return same structure

    Additional Resources

    Related Files

    • DATA_ACCESS.md - Comprehensive data access patterns
    • COMMON_PATTERNS.md - 10 production-tested patterns
    • ERROR_PATTERNS.md - Top 5 errors and solutions
    • BUILTIN_FUNCTIONS.md - Complete built-in reference

    n8n Documentation

    • Code Node Guide: https://docs.n8n.io/code/code-node/
    • Built-in Methods: https://docs.n8n.io/code-examples/methods-variables-reference/
    • Luxon Documentation: https://moment.github.io/luxon/

    Ready to write JavaScript in n8n Code nodes! Start with simple transformations, use the error patterns guide to avoid common mistakes, and reference the pattern library for production-ready examples.

    Recommended Servers
    Vercel Grep
    Vercel Grep
    OpenZeppelin
    OpenZeppelin
    Codeinterpreter
    Codeinterpreter
    Repository
    czlonkowski/n8n-skills
    Files