n8n-code-nodes

Write JavaScript or Python code in n8n Code nodes. Use this skill whenever the user needs to write, debug, or optimize code running inside an n8n Code node — including data transformations, aggregations, API calls with $helpers.httpRequest(), date manipulation with DateTime/Luxon, regex filtering, custom business logic, or any JavaScript/Python code that runs within a workflow. Also trigger when the user mentions $input, $json, $node, $helpers, _input (Python), Code node return format [{json: {...}}], "Run Once for All Items" vs "Run Once for Each Item" mode, or is troubleshooting Code node errors like "Cannot read property of undefined", empty return, or incorrect output format. For n8n expression syntax (the {{$json.field}} used in non-code nodes), defer to n8n-node-expert. For workflow design and architecture, defer to n8n-workflow-architect.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "n8n-code-nodes" with this command: npx skills add gerardloupecyb/skills/gerardloupecyb-skills-n8n-code-nodes

n8n Code Nodes

Write production-quality JavaScript and Python code inside n8n Code nodes. JavaScript is recommended for 95% of use cases; Python is available for specific needs.

When to Use Other Skills

  • Expression syntax ({{ }}) in non-code node fields → use n8n-node-expert
  • Workflow design, patterns, MCP tools → use n8n-workflow-architect
  • Writing code inside Code nodes → you're in the right place

When to Use Code Node vs Other Nodes

Use Code node for:

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

Use simpler nodes instead:

  • Simple field mapping → Set node
  • Basic filtering → Filter node
  • Simple if/else → IF or Switch node
  • HTTP requests only → HTTP Request node

JavaScript (Primary Language)

Quick Start Template

const items = $input.all();

const processed = items.map(item => ({
  json: {
    ...item.json,
    processed: true,
    timestamp: new Date().toISOString()
  }
}));

return processed;

Three Critical Rules

1. Return format: always [{json: {...}}]

✅ return [{json: {result: "success"}}];
✅ return items.map(item => ({json: item.json}));
✅ return [];  // empty result

❌ return {json: {result: "success"}};     // missing array wrapper
❌ return [{result: "success"}];            // missing json key
❌ return "processed";                      // plain string

2. Webhook data is under .body

❌ const email = $json.email;
✅ const email = $json.body.email;

3. No expression syntax {{ }} — use JavaScript directly

❌ const value = "={{$json.field}}";
✅ const value = $json.field;
✅ const value = $input.first().json.field;

Mode Selection

Run Once for All Items (default, recommended for 95% of cases):

  • Code executes once, receives all items
  • Access: $input.all(), $input.first()
  • Use for: aggregation, filtering, batch processing, comparing 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}}];

Run Once for Each Item (specialized):

  • Code executes separately per item
  • Access: $input.item
  • Use for: per-item API calls, independent validation
const item = $input.item;
return [{json: {...item.json, processed: true}}];

Data Access Patterns

$input.all() — Get all items (most common):

const items = $input.all();
const filtered = items.filter(item => item.json.status === 'active');
return filtered.map(item => ({json: {id: item.json.id, name: item.json.name}}));

$input.first() — Get first item:

const data = $input.first().json;
return [{json: {result: processData(data)}}];

$node — Reference other nodes:

const webhookData = $node["Webhook"].json;
const apiData = $node["HTTP Request"].json;
return [{json: {combined: {webhook: webhookData, api: apiData}}}];

Built-in Functions

$helpers.httpRequest() — HTTP calls from Code:

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

DateTime (Luxon) — Date operations:

const now = DateTime.now();
const formatted = now.toFormat('yyyy-MM-dd');
const nextWeek = now.plus({days: 7}).toFormat('yyyy-MM-dd');
const parsed = DateTime.fromISO($json.created_at).toFormat('MMMM dd, yyyy');
return [{json: {today: formatted, nextWeek, parsed}}];

$jmespath() — JSON queries:

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

Production Patterns

1. Data Transformation & Enrichment

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?.toLowerCase(),
      created_at: new Date().toISOString()
    }
  };
});

2. Multi-Source Aggregation

const items = $input.all();
const bySource = {};

for (const item of items) {
  const source = item.json.source || 'unknown';
  if (!bySource[source]) bySource[source] = {count: 0, total: 0};
  bySource[source].count++;
  bySource[source].total += item.json.amount || 0;
}

return [{json: {summary: bySource, timestamp: new Date().toISOString()}}];

3. Regex Extraction

const text = $input.first().json.body.message;
const emailPattern = /[\w.-]+@[\w.-]+\.\w+/g;
const emails = text.match(emailPattern) || [];
const urlPattern = /https?:\/\/[^\s]+/g;
const urls = text.match(urlPattern) || [];

return [{json: {emails, urls, hasAttachments: emails.length > 0 || urls.length > 0}}];

4. Top-N Filtering & Ranking

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. Threat Indicator Scoring

Pattern for security automation — score multiple indicators and produce confidence level:

const alert = $input.first().json;
let score = 0;
const reasons = [];

// Domain reputation
if (alert.sender_domain && KNOWN_BAD_DOMAINS.includes(alert.sender_domain)) {
  score += 0.4;
  reasons.push('known malicious domain');
}

// Attachment analysis
if (alert.has_attachment && /\.(exe|scr|bat|cmd|ps1)$/i.test(alert.attachment_name)) {
  score += 0.3;
  reasons.push('dangerous attachment type');
}

// SPF/DKIM
if (alert.spf_result === 'fail') { score += 0.15; reasons.push('SPF failure'); }
if (alert.dkim_result === 'fail') { score += 0.15; reasons.push('DKIM failure'); }

const confidence = score > 0.8 ? 'high' : score > 0.4 ? 'medium' : 'low';
return [{json: {score, confidence, reasons, alert_id: alert.id}}];

6. PDF/Report Data Parsing

Pattern for extracting structured data from API responses or parsed documents:

const rawData = $input.first().json;

// Extract metrics from parsed report sections
const metrics = {
  emails_blocked: parseInt(rawData.summary?.match(/(\d+)\s+emails?\s+blocked/i)?.[1] || '0'),
  phishing_detected: parseInt(rawData.summary?.match(/(\d+)\s+phishing/i)?.[1] || '0'),
  users_trained: parseInt(rawData.training?.match(/(\d+)\s+completed/i)?.[1] || '0'),
  compliance_score: parseFloat(rawData.compliance?.match(/([\d.]+)%/)?.[1] || '0')
};

return [{json: {metrics, report_date: DateTime.now().toFormat('yyyy-MM'), raw_sections: Object.keys(rawData)}}];

7. Quebec Tax Calculation

const expense = $input.first().json;
const amount = parseFloat(expense.amount);
const TPS_RATE = 0.05;     // Federal GST
const TVQ_RATE = 0.09975;  // Quebec QST

let taxBreakdown;
if (expense.province === 'QC' && expense.category === 'restaurant') {
  // Quebec restaurant: separate TPS and TVQ
  const subtotal = amount / (1 + TPS_RATE + TVQ_RATE);
  taxBreakdown = {
    subtotal: subtotal.toFixed(2),
    tps: (subtotal * TPS_RATE).toFixed(2),
    tvq: (subtotal * TVQ_RATE).toFixed(2),
    total: amount.toFixed(2),
    tax_type: 'QC_TPS_TVQ'
  };
} else if (expense.is_foreign_saas) {
  taxBreakdown = {
    subtotal: amount.toFixed(2),
    tps: '0.00',
    tvq: '0.00',
    total: amount.toFixed(2),
    tax_type: 'FOREIGN_NO_ITC',
    note: 'Foreign SaaS - no input tax credit'
  };
} else {
  // Standard GST/HST
  const rate = expense.province === 'QC' ? TPS_RATE + TVQ_RATE : 0.13; // HST for ON etc.
  const subtotal = amount / (1 + rate);
  taxBreakdown = {
    subtotal: subtotal.toFixed(2),
    tax: (amount - subtotal).toFixed(2),
    total: amount.toFixed(2),
    tax_type: expense.province === 'QC' ? 'QC_COMBINED' : 'HST'
  };
}

return [{json: {...expense, ...taxBreakdown}}];

Error Prevention

Always validate input:

const items = $input.all();
if (!items || items.length === 0) return [];
if (!items[0].json) return [{json: {error: 'Invalid input format'}}];

Use try-catch for external calls:

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}}];
}

Use optional chaining:

❌ const email = item.json.user.email;          // crashes if user is undefined
✅ const email = item.json?.user?.email || '';   // safe

Debug with console.log:

console.log(`Processing ${items.length} items`);
console.log('First item:', JSON.stringify(items[0].json, null, 2));

For complete pattern library, see references/js-patterns.md For complete error guide, see references/js-errors.md For built-in function reference, see references/js-builtins.md


Python (Secondary — Use When Needed)

Python in n8n Code nodes is in beta. Use JavaScript unless you specifically need Python standard library features or are significantly more comfortable with Python.

Key Differences from JavaScript

FeatureJavaScriptPython
Data access$input.all()_input.all()
Current item$input.item_input.item
Node reference$node["Name"].json_node["Name"].json
HTTP requests$helpers.httpRequest()Not available — use urllib
DateTimeDateTime (Luxon)datetime (standard library)
Return format[{json: {...}}][{"json": {...}}]

Quick Start

items = _input.all()

processed = []
for item in items:
    processed.append({
        "json": {
            **item["json"],
            "processed": True,
            "timestamp": datetime.now().isoformat()
        }
    })

return processed

Python Limitations in n8n

  • No external packages (no pip install) — standard library only
  • No $helpers.httpRequest() — use urllib.request instead
  • No Luxon DateTime — use Python's datetime
  • Less community support and documentation
  • Performance may vary

When Python Makes Sense

  • Complex text processing (Python's regex and string handling)
  • Statistical calculations (using statistics module)
  • Data parsing with json, csv, xml standard modules
  • When you have existing Python logic to port

For complete Python guide, see references/python-guide.md


Deployment Checklist

  • Code is not empty, has meaningful logic
  • Return statement exists on all code paths
  • Return format: [{json: {...}}]
  • No {{ }} expression syntax (use JS/Python directly)
  • Webhook data accessed via .body
  • Null/undefined guards (optional chaining or explicit checks)
  • Error handling (try-catch for external calls)
  • Mode selected ("All Items" for most cases)
  • Tested with real data

Reference Files

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Web3

crypto-report

No summary provided by upstream source.

Repository SourceNeeds Review
-758
aahl
Web3

agentwallet

No summary provided by upstream source.

Repository SourceNeeds Review
Web3

valtio-define

No summary provided by upstream source.

Repository SourceNeeds Review
-434
hairyf