N8n Code Nodes Official logo

N8n Code Nodes Official

Organization
n8n-io
n8n-code-nodes-official

Use when the user reaches for a Code node, mentions writing JavaScript or Python in n8n, or any custom logic comes up in workflow design. Triggers on "Code node", "Code", "JavaScript", "Python", "custom logic", "transform data", "$input", "$json transformation", "loop in code", "write a function", or any time the obvious answer seems to be "just put it in code."

Overview

Publishern8n-io
Repositoryskills
Skill namen8n-code-nodes-official
Stars
551
Forks
80
Bundled files
3
LicenseApache-2.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 3 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by n8n-io on GitHub. Read the source before you install it.

Installation

Install the N8n Code Nodes Official AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/n8n-io/skills/tree/main/skills/n8n-code-nodes-official
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/n8n-io/skills.git /tmp/skills
mkdir -p .claude/skills
cp -r /tmp/skills/skills/n8n-code-nodes-official .claude/skills/n8n-code-nodes-official
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable N8n Code Nodes Official in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads N8n Code Nodes Official on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so N8n Code Nodes Official is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

n8n Code Nodes

The Code node is powerful and often the wrong tool. The n8n equivalent of dropping into raw SQL when an ORM would do: real cases exist, but the moment a Code node handles logic an expression could, the workflow is harder to read, debug, and maintain. There's also a real perf gap: Code runs in a sandboxed JS runtime, expressions and Edit Fields run in-process, and the per-invocation overhead can be hundreds of times higher in Code (anecdotally ~2ms vs ~600ms for equivalent logic). For hot paths and large item counts, that compounds.

Strong defaults

  1. Code node is a last resort. Decision order: expression ({{...}}) → arrow function inside Edit Fields → Code node. The first two paths cover most "transform this data" tasks. Code earns its place for multi-source aggregation, external libraries, and a few specific patterns documented below.

  2. Default to JavaScript. Write JS unless the user explicitly asked for Python ("use Python here," "I'm a Python shop," pasted Python code). Everywhere else in n8n (expressions, Edit Fields) is JS, JS has a curated library allowlist (lodash, crypto, luxon).

Decision tree

Need custom logic?
├── Is it a transformation of one or two fields?
│   └── Expression: {{ $json.foo.toUpperCase() }} or {{ $json.items.map(item => item.name).join(', ') }}
│       Most "just transform this" cases land here.
│
├── Is it multi-line, but pure data shaping (map, filter, reduce, conditional)?
│   └── Edit Fields with arrow function expression. See references/ARROW_FUNCTIONS_IN_EDIT_FIELDS.md
│
├── Does it need full statements, multiple data sources, or external libs?
│   ├── Are you SURE the above two don't work?
│   │   └── Re-read the parent. The bar is high.
│   └── Yes, genuinely needs it
│       └── Code node. See references/JAVASCRIPT_PATTERNS.md
│
└── Is it actually two separate transformations stitched together?
    └── Use two nodes (Edit Fields → Edit Fields, or Edit Fields → IF). Composability beats one big Code block.

For the full decision logic with examples for each branch, see references/DECISION_TREE.md.

What expressions can do that people forget

Common reaches-for-Code-node that should be expressions:

ts
// ❌ Code node
return { name: $input.first().json.name.toUpperCase() }

// ✅ Expression in Edit Fields, "name" field
{{ $json.name.toUpperCase() }}
ts
// ❌ Code node
const items = $input.first().json.items
return { tags: items.map(item => item.tag).filter(tag => tag).join(', ') }

// ✅ Expression
{{ $json.items.map(item => item.tag).filter(tag => tag).join(', ') }}
ts
// ❌ Code node
const date = new Date($input.first().json.created_at)
return { formatted: date.toISOString().slice(0, 10) }

// ✅ Expression with n8n's date extension
{{ $json.created_at.toDateTime().format('yyyy-MM-dd') }}

For more on what expressions can express, see the n8n-expressions-official skill.

What arrow-functions-in-Edit-Fields can do

Edit Fields assigns field values via expression. Inline arrow functions get you most multi-line logic without the Code node:

ts
// In Edit Fields, "summary" field:
{{ (() => {
    const items = $json.items
    const total = items.reduce((sum, item) => sum + item.price, 0)
    const tax = total * 0.08
    return `Total: $${(total + tax).toFixed(2)}`
})() }}

Right tool for "logic slightly too gnarly for a one-liner." See references/ARROW_FUNCTIONS_IN_EDIT_FIELDS.md for patterns and formatting.

When the Code node IS the right answer

Real uses exist. Bar is high, not "never." The cases below are legitimate. Build with code without apologizing.

Multi-source aggregation across the whole dataset

When a node needs to:

  • Read from multiple upstream nodes simultaneously (e.g., $('Source A').all(), $('Source B').all(), $('Source C').first().json).
  • Compute statistics or transformations across all items at once (not per-item).
  • Apply multi-step logic with intermediate data structures (lookup maps, accumulators, ratios).

Most common valid case. Examples:

  • Analytics rollups: per-group averages, percentile scoring, normalization across categories.
  • Building lookup tables from one source and joining against rows from another.
  • Computing offsets/ratios across two reference datasets, then applying to a third.
ts
// Real-world shape: aggregate test results from one source,
// model metadata from another, category mapping from a third,
// and produce per-model-per-category averages.

const testResults = $('Get Test Results').all().map(item => item.json)
const models = $('Get Models').all().map(item => item.json)
const categoryMap = $('Get Category Map').first().json.testCategoryMap

const categoryByTestId = Object.fromEntries(
    categoryMap.map(mapping => [mapping.testId, mapping.category])
)

const result = models.map(model => {
    const modelTests = testResults.filter(test => test.modelId === model.id)
    const stats = modelTests.reduce((acc, test) => {
        const cat = categoryByTestId[test.testId]
        if (!cat) return acc
        acc[cat] ??= { scored: 0, available: 0, count: 0 }
        acc[cat].scored += test.pointsScored ?? 0
        acc[cat].available += test.pointsAvailable ?? 0
        acc[cat].count += 1
        return acc
    }, {})

    const averages = Object.fromEntries(
        Object.entries(stats).map(([category, stat]) => [
            category,
            { avg: stat.available > 0 ? stat.scored / stat.available : 0, n: stat.count }
        ])
    )

    return { modelId: model.id, modelName: model.modelName, ...averages }
})

return result.map(json => ({ json }))

Technically expressions can reach across items via $('Node Name').all() and reduce inline, but for anything with this much shape (joins, group-bys, nested aggregation) the result is a one-line megaexpression that's hard to read and impossible to debug. Use Code.

External libraries

JS Code can require from a curated allowlist (lodash, etc.), but expressions can't.

Always check for a native node first. n8n has more native nodes than people realize. Dropping into Code for something with a native node is a recurring mistake. The next two subsections cover the specific traps.

Cryptographic operations: use the Crypto node, not Code

HMAC, signing, hashing, encryption: n8n has a native Crypto node (n8n-nodes-base.crypto). Use it. It handles SHA256, MD5, HMAC, encrypt/decrypt, and random generation, all without writing JavaScript.

ts
// WRONG (recurring AI slip):
const crypto = require('crypto')
const hash = crypto.createHash('sha256').update(buf).digest('hex').slice(0, 12)

// RIGHT: configure the Crypto node with operation: 'hash', type: 'SHA256'
//   then read $('Hash').item.json.<output> downstream.

The Code-with-require('crypto') pattern is one of the most common false positives for "this needs a Code node." It doesn't. The Crypto node covers it.

Hashing binary, not strings

Don't reach for Code just because you need to hash binary (a PDF, an image, a file buffer). The Crypto node has a binaryPropertyName parameter. Point it at the binary slot key and it hashes the buffer directly. You don't need this.helpers.getBinaryDataBuffer(...) in user code.

ts
// WRONG (recurring AI slip with binary):
const crypto = require('crypto')
const buf = await this.helpers.getBinaryDataBuffer($itemIndex, 'data')
const hash = crypto.createHash('sha256').update(buf).digest('hex')

// RIGHT: Crypto node configured to hash binaryPropertyName='data', SHA256.
//   Then $('Crypto').item.json.<output> has the hash; chain a Set node for any field shaping.

The remaining valid Code-for-crypto case: a non-standard signing scheme that the Crypto node doesn't expose (e.g., a custom AWS-style signature), AND httpCustomAuth credential doesn't fit either. Rare. Justify explicitly.

XML / SOAP / RSS parsing: use the XML node, not Code

n8n has a native XML node (n8n-nodes-base.xml) with parse and stringify operations. It already converts XML to JSON. Once it has, the result is plain JSON and Edit Fields with arrow function expressions handles all the field extraction, array normalization (Array.isArray(...) ? ... : ...), and link-finding (.find()) you'd reach for Code to do.

ts
// WRONG (recurring AI slip):
// XML node already parsed → another Code node to extract a few fields:
const entry = $('Parse XML').item.json.feed.entry
const firstEntry = Array.isArray(entry) ? entry[0] : entry
return { json: { title: firstEntry.title, url: firstEntry.link.find(link => link.type === 'pdf').href } }

// RIGHT: Edit Fields with arrow function expressions:
//   title:  ={{ (() => { const entry = $('Parse XML').item.json.feed.entry; return Array.isArray(entry) ? entry[0].title : entry.title; })() }}
//   pdfUrl: ={{ $('Parse XML').item.json.feed.entry.link.find(link => link.type === 'pdf')?.href }}

If the field-extraction logic is genuinely too gnarly for inline expressions even with multi-line arrow functions, the next stop is Edit Fields with a single multi-line arrow function, NOT a Code node. See references/ARROW_FUNCTIONS_IN_EDIT_FIELDS.md.

What these have in common

Valid cases are about scope: whole-dataset, multiple sources, or stateful constructs single-item tools can't reach. Invalid cases: Code doing what an expression could, OR what a native node already does.

Quick tests:

  • "Could I describe this Code node's job as 'take this one item and...'?" If yes, wrong tool.
  • "Is there a native node for this?" Search via search_nodes first. Crypto, XML, JSON parsing, date math (Luxon), HTTP calls, file I/O, regex matching: all have native nodes or expression-level support.

JavaScript Code node specifics

Two modes:

  • Run Once for All Items (default, use this): runs once with $input.all(). If you need per-item logic, just for (const item of $input.all()) inside. This is the standard shape and almost always what you want.
  • Run Once for Each Item: runs once per item with $input.first() (or $input.item).

Common shape:

ts
// Run Once for All Items
const items = $input.all()
const totals = items.map(item => ({
  ...item.json,
  total: item.json.qty * item.json.price,
}))
return totals.map(json => ({ json }))

The return must be an array of { json: ... } objects (or { json: ..., binary: ... }), not raw JSON.

For binary handling, error patterns, and Code-node-only bugs, see references/JAVASCRIPT_PATTERNS.md.

Reference files

FileRead when
references/DECISION_TREE.mdYou're tempted to use a Code node and want to verify the simpler paths really don't work
references/ARROW_FUNCTIONS_IN_EDIT_FIELDS.mdThe transformation is multi-line but pure data shaping
references/JAVASCRIPT_PATTERNS.mdCode node is genuinely needed and JS is the language

Anti-patterns

Anti-patternWhat goes wrongFix
Code node doing return { x: $input.first().json.x.toUpperCase() }Whole node for one expressionReplace with an Edit Fields expression
Code node building HTML strings for an email bodyThe Email node's body field accepts expressionsInline the expression into the email node
Code node using new Date() for date formattingLoses to Luxon's clarityUse Luxon in expression. See n8n-expressions-official
Set node + Code node combo (Set builds inputs, Code transforms)Two nodes for what should be one Edit FieldsCollapse into one Edit Fields with arrow function
Pasting credentials/tokens into Code node textSame leak as text fieldsUse credentials, not Code node

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the N8n Code Nodes Official AI skill do?

Use when the user reaches for a Code node, mentions writing JavaScript or Python in n8n, or any custom logic comes up in workflow design. Triggers on "Code node", "Code", "JavaScript", "Python", "custom logic", "transform data", "$input", "$json transformation", "loop in code", "write a function", or any time the obvious answer seems to be "just put it in code."

Why use N8n Code Nodes Official on TypingMind?

Because you install it once and use it with any model. N8n Code Nodes Official is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install N8n Code Nodes Official in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/n8n-io/skills/tree/main/skills/n8n-code-nodes-official. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use N8n Code Nodes Official?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with N8n Code Nodes Official?

As many as you like. As long as a model supports skills, you can use N8n Code Nodes Official with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the N8n Code Nodes Official AI skill free?

Yes. It is published on GitHub by n8n-io under the Apache-2.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇