agentleFS
neurawork-gitneurawork-git/n8n-autopilot/skills/n8n-code-javascript/SKILL.md

n8n-code-javascript

Skill18 starsChanged 42 days agoMITView on GitHub

Write JavaScript code in n8n Code nodes. Use when writing JavaScript in n8n, using $input/$json/$node syntax, making HTTP requests with $helpers, working with dates using DateTime, troubleshooting Code node errors, or choosing between Code node modes.

22 other projects use a version of this, 15 of them edited.

Adopted by

Most recently taken up by

Used with

Projects with it also use n8n-code-tool, n8n-multi-instance and 7 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • czlonkowskiSkill

    n8n-code-tool

    Write JavaScript or Python for the n8n Custom Code Tool (@n8n/n8n-nodes-langchain.toolCode) — the AI-agent-callable tool, NOT the workflow Code node. Use when building a Code Tool attached to an AI Agent, writing code that an LLM will invoke, parsing the `query` input, returning a string result, defining an input schema for structured arguments (specifyInputSchema, jsonSchemaExample, DynamicStructuredTool), or troubleshooting errors like \"Wrong output type returned\", \"No execution data available\", \"The response property should be a string, but it is an object\", \"Cannot assign to read only property 'name'\", or an AI agent that refuses to call the tool. Covers the critical differences between Code node and Code Tool: return format (string vs `[{json:{...}}]`), unavailability of `$fromAI`/`$input`/`$helpers` in the Code Tool sandbox, naming rules for AI invocation, and when to use `toolWorkflow`/HTTP Request Tool instead.

    Also in 3 projects that use this

  • czlonkowskiSkill

    n8n-multi-instance

    Use when an n8n-mcp account targets more than one n8n instance — i.e. the `n8n_instances` tool is available, the user mentions multiple n8n instances or environments (prod vs staging, several teams or clients), several agents or chats work on one account in parallel, a workflow / datatable / credential / execution call returns an unexpected NOT_FOUND or reads data you don't recognize, or a call is refused with `INSTANCE_AMBIGUOUS` or `INSTANCE_NOT_FOUND`. Covers naming the target instance on each call with the `instance` argument, setting the default with `switch`, verifying the target before high-stakes work — credential writes above all — and recovering from misroutes and fail-closes. Always consult this skill before operating on a specific instance, before any credential create/update/delete on a multi-instance account, or when a call hits the wrong/empty data or an instance error.

    Also in 3 projects that use this

  • tmolaviSkill

    n8n-agents

    Use when building n8n AI Agent / LangChain clusters — tools, memory, RAG, structured output, system prompts, sub-workflow-as-tool, or fixing agent connection topology (ai_languageModel, ai_tool, ai_memory).

    Also in 3 projects that use this

  • tmolaviSkill

    n8n-error-handling

    Use for production n8n workflows, webhook APIs, retries, error outputs, error workflows, dead-letter patterns, and correct HTTP response status shapes for callers.

    Also in 3 projects that use this

  • BlockSkill

    frontend-design

    Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.

    Also in 4 projects that use this

  • +3 more from czlonkowski
  • +1 more from tmolavi

The file

We split this skill into the rules it gives an agent

6 rules. 0 are common, 2 are distinctive, and 4 are very specific to this project.

  • 0

    Common

    Most of the 22 edited versions we read keep these.

  • 2

    Distinctive

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    CRITICAL: Must return [{json: {...}}] format

    line 35
  2. Distinctive:

    Use a Code node when the logic genuinely has no native equivalent (custom parsing, multi-field computation, shaping a bespoke payload).

    line 61
  3. Very specific:

    If Code must use a builtin, the sticky note names the instance setting it depends on, and the push-lint gate warns (code-env-access) so the …

    line 216
  4. Very specific:

    Always validate input: if (!items || items.length === 0) return [].

    line 233
  5. Distinctive:

    Use try-catch for async operations

    line 234
  6. Very specific:

    Prefer map/filter over manual loops

    line 235

“Common” is measured: kept by at least 6 in 10 of the 22 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
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(), DateTime (Luxon), $jmespath()

When NOT to use a Code node (native-first)

Reach for a native node before writing JavaScript — Code nodes are harder to read, review, and they run V8 in-process (OOM risk on large data, see below). In a real production audit, Code nodes outnumbered native conditional nodes ~2.5:1 — much of it avoidable:

If you are doing…Use this native node, NOT Code
Branching on a conditionIF (2 branches) / Switch (n branches)
Dropping items by a ruleFilter
Setting / renaming / mapping fieldsSet (Edit Fields)
Merging / combining streamsMerge
Aggregating into one itemAggregate / Summarize
Looping over large batchesLoop Over Items (SplitInBatches)

Memory / OOM (real production incident): a Code node that loads or iterates a large dataset — especially a full DB result set (>~10k rows), binary, or file contents — can spike the V8 heap (~3 GB cap) and crash the n8n pod (OOM). For large data: page/limit at the source, process in SplitInBatches, or push the work into the database/native node instead of materializing it all in JS.

Use a Code node when the logic genuinely has no native equivalent (custom parsing, multi-field computation, shaping a bespoke payload).

Mode Selection Guide

Run Once for All Items (Recommended - Default)

Use for: aggregation, batch processing, transformations that have no native-node equivalent

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

Use for: Specialized cases — per-item validation, independent operations

const item = $input.item;

return [{
  json: { ...item.json, processed: true, processedAt: new Date().toISOString() }
}];

Decision: Need to compare multiple items? → All Items. Each item independent? → Each Item. Not sure? → All Items.


Data Access Patterns

// Most common: all items
const allItems = $input.all();

// Single result
const firstItem = $input.first();
const data = firstItem.json;

// Reference other nodes
const webhookData = $node["Webhook"].json;
const httpData = $node["HTTP Request"].json;

CRITICAL: Webhook Data Structure

Webhook data is nested under .body:

// ❌ WRONG
const name = $json.name;

// ✅ CORRECT
const name = $json.body.name;
const webhookData = $input.first().json.body;

Return Format Requirements

// ✅ Single result
return [{ json: { field1: value1 } }];

// ✅ Multiple results
return items.map(item => ({ json: { id: item.json.id, processed: true } }));

// ✅ Empty result
return [];

WRONG: return {json: {...}} (no array), return [{field: value}] (no json key)


Built-in Functions

$helpers.httpRequest()

const response = await $helpers.httpRequest({
  method: 'GET',
  url: 'https://api.example.com/data',
  headers: { 'Authorization': 'Bearer token' }
});

return [{ json: { data: response } }];

DateTime (Luxon)

const now = DateTime.now();
const formatted = now.toFormat('yyyy-MM-dd');
const tomorrow = now.plus({ days: 1 });

$jmespath()

const adults = $jmespath(data, 'users[?age >= `18`]');
const names = $jmespath(data, 'users[*].name');

Common Patterns

Aggregation

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

Filtering + Transformation

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

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

Hardened instances deny $env and require() (#97)

Production instances commonly run with N8N_BLOCK_ENV_ACCESS_IN_NODE=true and an empty NODE_FUNCTION_ALLOW_BUILTIN / NODE_FUNCTION_ALLOW_EXTERNAL. There, $env.SECRET throws access to env vars denied and require('crypto') throws Module crypto is disallowed — at runtime, after every gate was green. Do not build on either:

  • Secrets → a credential on a native node (HTTP Request with httpHeaderAuth, …), never $env.
  • HMAC / hashing → the Crypto node (n8n-nodes-base.crypto), not require('crypto').
  • If Code must use a builtin, the sticky note names the instance setting it depends on, and the push-lint gate warns (code-env-access) so the reviewer checks the target instance allows it.

Top 5 Mistakes

  1. No return statement → Add return items.map(item => ({json: item.json}));
  2. Using {{ }} in Code node → Use $json.field directly (no braces)
  3. Wrong return wrapper → Must be [{json: {...}}], not {json: {...}}
  4. Missing null checks → Use item.json?.user?.email || 'fallback'
  5. Webhook body → $json.email ❌ → $json.body.email ✅

Best Practices

  • Always validate input: if (!items || items.length === 0) return [];
  • Use try-catch for async operations
  • Prefer map/filter over manual loops
  • Filter early, process late
  • Debug with console.log()

When to Use Code Node

✅ Complex transformations, custom calculations, API response parsing, multi-step conditionals, data aggregation

❌ Simple field mapping → Set node | Basic filtering → Filter node | HTTP requests → HTTP Request node

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.