Agent skill

Native Python in n8n Code Nodes

by czlonkowski in czlonkowski/n8n-skills

Explains how to write native Python in n8n Code nodes, including the two input variables, blocked imports and fixes for common errors.

MITAuto-check passedProductivity & Automation

Install Native Python in n8n Code Nodes

skills CLI
$ npx skills add czlonkowski/n8n-skills --skill n8n-code-python -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install czlonkowski/n8n-skills n8n-code-python --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/czlonkowski/n8n-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/n8n-code-python .claude/skills/n8n-code-python && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
n8n-code-python
GitHub stars
6.4k
Token cost
~2.8k tokens
SKILL.md length
1,221 words
Files
3
Skills in repo
15
Repo updated
First seen
Licence
MIT

At a glance

Explains how to write native Python in n8n Code nodes, including the two input variables, blocked imports and fixes for common errors.

  • Writing Python in an n8n Code node when you explicitly want Python
  • SKILL.md covers JavaScript first — stronger…, Quick start, The only inputs: _items and… and Imports: blocked by default, plus 7 more sections
  • Calls python
  • Migrating old Pyodide Python code that used _input or _json

What it does

Since n8n 2.0, Python in the Code node runs as native Python in a task runner, with `language` set to `pythonNative`. The old Pyodide 'Python (Beta)' and its helpers such as `_input`, `_json`, `_node` and `_now` are gone and now raise `NameError`, which is why code copied from older templates often breaks. The skill advises JavaScript first and Python only when asked, because everything n8n-specific, such as node lookups, Luxon, HTTP helpers and static data, exists only in JavaScript.

It covers the only two inputs: `_items` in run-once-for-all-items mode and `_item` in run-once-for-each-item mode, both plain dicts with dict-only access. It also covers blocked imports by default, the sandbox's denied builtins, accepted return shapes, webhook payloads under `body` and how errors interact with onError. A COMMON_PATTERNS.md file adds worked examples. Python in the AI-agent Custom Code Tool is handled by a different skill, where the input is `_query`.

When your agent uses it

  • Writing Python in an n8n Code node when you explicitly want Python
  • Migrating old Pyodide Python code that used _input or _json
  • Fixing a Code node that fails with NameError or a security violation

Example prompts

  • “Write an n8n Python Code node that keeps only the items whose revenue is above the average.”
  • “My Code node fails with 'Import of standard library module is disallowed'. What can I do instead?”
  • “Convert this old Python (Beta) node that uses _input.all() to the native Python Code node.”

Requirements

  • n8n 2.x with the native Python task runner

What it can do on your machine

Read from SKILL.md and the folder at commit 19cd793. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • python

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Native Python in n8n Code Nodes loads about 2.8k tokens when it runs. Until then it costs about 236 tokens; SKILL.md has 1,221 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~236
When it runs · the whole SKILL.md, loaded when a task matches
~2.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from czlonkowski/n8n-skills at commit 19cd793, republished under its MIT licence (© czlonkowski). 1,221 words, ~2,759 tokens.

Download SKILL.mdSave it as .claude/skills/n8n-code-python/SKILL.md (or your agent's skills folder). This skill also uses 2 other files; get the full folder from GitHub.
name
n8n-code-python
description
Write Python in n8n Code nodes (native Python, `language` pythonNative, n8n 2.x). Use when the user explicitly wants Python in a Code node, when migrating old Pyodide/"Python (Beta)" code that used _input/_json/_node/_now, or when a Python Code node fails with NameError, "Security violations detected", "Import of standard library module … is disallowed", "__build_class__ not found", "A 'json' property isn't a dictionary", or "Python runner unavailable". Covers the only two variables (_items/_item), dict-only access, imports blocked by default, the sandbox's denied builtins, accepted return shapes, and how errors interact with onError. JavaScript is the default for Code nodes — native Python has no n8n helpers and, by default, no imports. EXCEPTION — for Python in the AI-agent-callable Custom Code Tool (@n8n/n8n-nodes-langchain.toolCode), use the n8n-code-tool skill instead (input is _query, return must be a string).

Python Code Node (native)

Since n8n 2.0 the Code node's Python runs as native Python in a task runner (language: "pythonNative"). The old Pyodide "Python (Beta)" is gone, and with it every n8n helper it had: _input, _json, _node, _now, _today and _jmespath all raise NameError now. Code copied from old templates, forum posts or older docs usually breaks on this.


JavaScript first — stronger than before

Native Python gives you two variables and plain Python, and by default no imports: no json, datetime or re. Everything n8n-specific ($('Node'), $jmespath, Luxon, this.helpers.httpRequest, static data) exists only in JavaScript. Use Python only when the user explicitly asks for it. Even then, first check whether an expression, Edit Fields, or a native node (Crypto, Date & Time, HTML, XML) does the job. See n8n-code-javascript and the transform gatekeeper in n8n-expression-syntax.


Quick start

python
# Run Once for All Items (default mode)
return [
    {"json": {"name": it["json"]["name"], "revenue": it["json"]["revenue"]}}
    for it in _items
    if it["json"].get("active")
]
python
# Run Once for Each Item
row = _item["json"]
return {"json": {**row, "name_upper": (row.get("name") or "").upper()}}

Node config: {"language": "pythonNative", "mode": "runOnceForAllItems" | "runOnceForEachItem", "pythonCode": "..."} on n8n-nodes-base.code typeVersion 2.


The only inputs: _items and _item

ModeVariableShape
Run Once for All Items_itemslist of plain dicts {"json": {...}, "pairedItem": {...}}
Run Once for Each Item_itemone plain dict {"json": {...}, "pairedItem": {...}}
  • Each variable exists only in its own mode. _items in each-item mode (or _item in all-items mode) raises NameError.
  • Dict access only. it["json"]["name"] or it["json"].get("name"). it.json.name raises AttributeError: 'dict' object has no attribute 'json'.
  • No other nodes. There is no _node / $('Node') equivalent. If you need data from another branch, bring it in with Merge first, or read it in JavaScript.
  • Webhook payloads are under ["body"]: _items[0]["json"].get("body", {}).get("email").
  • Binary data isn't covered here. Read and write binary in JavaScript (see n8n-binary-and-data).
  • pairedItem: returning _items / _item keeps it. When you build new dicts and downstream uses $('Node').item, add "pairedItem": {"item": i} to each returned item. That isn't verified on native Python yet, so test-run before relying on it.
  • Missing keys: prefer .get(key, default). row["missing"] raises KeyError.

Migration table for legacy code:

Legacy (Pyodide)Native
_input.all()_items
_input.first()["json"]_items[0]["json"] (guard if _items)
_input.item / _json_item / _item["json"]
_node["X"]not available: Merge upstream, or use JS
_now, _todaynot available: pass {{ $now.toISO() }} in via Edit Fields, or use JS
_jmespath(data, q)not available: $jmespath in an expression, or a comprehension
item.json.fielditem["json"]["field"]

Imports: blocked by default

Every import (standard library and third-party) is checked against an allowlist before the code runs. The default allowlist is empty, so even import json rejects the whole node:

Security violations detected
Line 1: Import of standard library module 'json' is disallowed. Allowed stdlib modules: none
  • n8n Cloud: no imports at all.
  • Self-hosted: the admin can allowlist modules in the task-runner config (see n8n-self-hosting → TASK_RUNNERS.md). Some instances therefore allow json, datetime and re, and most don't.
  • Default to import-free code. If an import would really help, confirm it first: a one-line test node import json + return [{"json": {"ok": True}}], or ask the user. Never assume.
  • Without imports: parse JSON strings upstream ({{ JSON.parse($json.payload) }} in Edit Fields). Do date math in expressions (Luxon) or JS. ISO-8601 strings still compare and sort correctly as plain strings. Use the Crypto node for hashing.
  • requests, pandas and numpy are never available unless the admin built a custom runner image. Use the HTTP Request node for HTTP.

Sandbox limits (these fail even without imports)

You writeWhat happensUse instead
eval, exec, compile, open, input, type, getattr, setattr, hasattr, vars, dir, globals, locals, object, memoryview, breakpointNameError: name 'type' is not defined (runtime)isinstance(x, dict); key in d / d.get(key)
class Foo: ...__build_class__ not found (runtime)dicts + functions
x.__class__, "{0.__class__}".format(x), __import__("json")Security violations detected (whole node rejected before running)—
global counter inside a functionNameError: name 'counter' is not defined, because your code runs inside a wrapper functionnonlocal counter

Everything else in plain Python works (verified): comprehensions, generators, lambdas, closures, recursion, try/except, f-strings / .format() / %, sorted/min/max/sum/any/all/ enumerate/zip/round, sets, isinstance, print() (output goes to the browser console).


Return shapes (verified)

Observed on n8n 2.38.5. The auto-wrapping and passthrough behaviours below are undocumented and could change in a later release. Re-check with a test run after upgrading n8n.

Run Once for All Items

ReturnResult
[{"json": {...}}, ...]canonical, N items
[{...}, ...] (plain dicts)auto-wrapped under json, N items
{"json": {...}} or a single plain dict1 item
_items (mutated in place)passthrough with your changes
None / no returnerror Cannot read properties of null (reading 'json')

Run Once for Each Item

ReturnResult
{"json": {...}}, a plain dict, or _item1 item
Nonethe item is dropped (a built-in filter)
a listerror A 'json' property isn't a dictionary [item 0]

Value conversion on output: tuple becomes a list, set becomes the string "{1, 2}", and a datetime becomes str(dt) ("2026-09-16 10:18:00.025792", not ISO). Convert explicitly (sorted(s), dt.isoformat()).

Prefer the explicit [{"json": ...}] in all-items mode and {"json": ...} in each-item mode. The auto-wrapping works, but the explicit shape makes the intent obvious to the next reader.


Show full SKILL.md (443 more words)Show less

Errors and onError

A plain raise ValueError("bad row") fails the node with that message. When the node has an onError continue mode, the three failure kinds behave differently (verified):

FailurecontinueErrorOutputcontinueRegularOutput
Runtime exception (raise, KeyError, NameError, denied builtin){"error": "<message>"} on the error output (main[1]) ✅{"error": "<message>"} on the main output
Static rejection (Security violations detected: import, dunder)node marked failed, but the input items, unchanged, go out the success output; main[1] stays emptyinput items, unchanged, on the main output
Bad return shape (list in each-item mode, None in all-items mode)same: unchanged input on the success outputsame

The last two are silent-data traps: downstream nodes receive unprocessed input as if the code had run, and the execution still shows success. No error branch catches them. Prevent them (no imports unless confirmed, correct return shape) and confirm with a real test run, checking the Code node's status and output (see n8n-error-handling).

Other messages:

  • Python runner unavailable: Python 3 is missing from this system: the self-hosted instance has no Python task runner (the stock image ships none). It's an infrastructure problem, not a code problem. See n8n-self-hosting → TASK_RUNNERS.md.
  • validate_node / validate_workflow catch a few Python mistakes (import requests, missing return, return None). They do not catch _input/_json, dot access, blocked stdlib imports, dunder access or classes. A test execution is the only reliable check.

Performance

Each Python Code node costs roughly 0.4 s (about 1 s when the runner is cold), noticeably more than a JS Code node or an expression. Process lists in Run Once for All Items mode rather than per item, and don't chain several small Python nodes where one would do.


Checklist

  • The user actually asked for Python. Otherwise JS, an expression, or a native node.
  • Mode matches the variable: _items (all items) / _item (each item).
  • Only dict access. No _input, _json, _node, _now or _jmespath.
  • No import unless confirmed allowlisted on this instance.
  • No classes, type(), getattr/hasattr or dunders. nonlocal instead of global.
  • Return shape fits the mode. Sets and datetimes converted explicitly.
  • Ran a real test execution and inspected the output items (validation alone won't catch the traps above).

Reference

  • COMMON_PATTERNS.md: 12 import-free patterns, each verified on a live n8n instance (filter, aggregate, group, dedupe, top N, flatten, validate, drop items, text report, safe nested access, running totals, ISO timestamps).
  • n8n-code-javascript: the default for Code nodes, with all n8n helpers.
  • n8n-expression-syntax: $jmespath, Luxon and the transform gatekeeper, often a better fit than any Code node.
  • n8n-code-tool: Python in the AI-agent Custom Code Tool (_query, returns a string).
  • n8n-error-handling: wiring error outputs; the passthrough trap above.
  • n8n-self-hosting: enabling the Python task runner and allowlisting modules.

© czlonkowski, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 2 other files in skills/n8n-code-python of czlonkowski/n8n-skills.

  • SKILL.md
  • COMMON_PATTERNS.md
  • README.md

Open the folder on GitHubat commit 19cd793

Compare with similar skills

Native Python in n8n Code Nodes next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Native Python in n8n Code Nodes compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Native Python in n8n Code Nodes this skillczlonkowski/n8n-skills6.4k—~2.8kAutomated safety check: PassMIT
N8n Code Pythondavila7/claude-code-templates32k7 repos~4.5kAutomated safety check: PassMIT
N8n Code Toolsickn33/agentic-awesome-skills47k1 repos~4.1kAutomated safety check: PassMIT
N8n Code Javascriptdavila7/claude-code-templates32k4 repos~4kAutomated safety check: PassMIT
VectCutAPI Video Editingsun-guannan/VectCutAPI2.3k—~2.1kAutomated safety check: PassApache-2.0
Skyvern Browser AutomationSkyvern-AI/skyvern23k—~1.9kAutomated safety check: PassAGPL-3.0

Similar skills

  • N8n Code Python

    davila7/claude-code-templates

    Write Python code in n8n Code nodes. An agent skill from davila7/claude-code-templates.

    32k GitHub starsUsed in 7 repos~4.5k tokens
    Productivity & AutomationAuto-check passed
  • N8n Code Tool

    sickn33/agentic-awesome-skills

    Write and debug JavaScript or Python for the AI-callable n8n Custom Code Tool, including schemas, sandbox limits, and return formats.

    47k GitHub starsUsed in 1 repo~4.1k tokens
    Productivity & AutomationAuto-check passed
  • N8n Code Javascript

    davila7/claude-code-templates

    Write JavaScript code in n8n Code nodes. An agent skill from davila7/claude-code-templates.

    32k GitHub starsUsed in 4 repos~4k tokens
    Productivity & AutomationAuto-check passed
  • VectCutAPI Video Editing

    sun-guannan/VectCutAPI

    Drives CapCut or JianYing through an HTTP and MCP API: create drafts, add video, audio, text, subtitles and effects, preview on the web and batch-produce videos.

    2.3k GitHub stars~2.1k tokensUpdated 4 days ago
    Media & CreativeAuto-check passed
  • Skyvern Browser Automation

    Skyvern-AI/skyvern

    Automates websites with Skyvern's AI browser agent to fill forms, extract data, download files, log in and run multi-step workflows through SDKs, REST, MCP or a CLI.

    23k GitHub stars~1.9k tokensUpdated yesterday
    Productivity & AutomationAuto-check passed
  • Robocorp Automation

    robocorp/robocorp

    Bootstrap from an empty folder or build, debug, locally run, and validate Python automations built with Robocorp or Sema4.ai tooling, robocorp.tasks, rcc, robocorp-browser, and RPA Framework.

    653 GitHub stars~2.4k tokensUpdated 6 days ago
    Productivity & AutomationAuto-check passed

More from czlonkowski/n8n-skills

All 15 skills in this repo
  • n8n Binary Data Handling

    czlonkowski/n8n-skills

    Explains how n8n keeps file bytes in $binary apart from structured $json data, and how to read, write and preserve binary across nodes, agent tools and chat.

    6.4k GitHub stars~3.9k tokensUpdated 21 days ago
    Auto-check passed
  • n8n Code Node JavaScript

    czlonkowski/n8n-skills

    Guides writing JavaScript in n8n Code nodes: picking an execution mode, reading input data, returning items, using built-in helpers and avoiding common errors.

    6.4k GitHub stars~4.9k tokensUpdated 21 days ago
    Auto-check passed
  • n8n Custom Code Tool Guide

    czlonkowski/n8n-skills

    Explains the n8n Custom Code Tool's actual runtime contract so an AI-agent-callable tool doesn't get written like a regular workflow Code node.

    6.4k GitHub stars~4k tokensUpdated 21 days ago
    Auto-check passed
  • n8n Error Handling

    czlonkowski/n8n-skills

    Wires n8n workflows so failures are visible and recoverable: per-node error outputs, retries, error workflows and correct 4xx and 5xx webhook responses.

    6.4k GitHub stars~5.1k tokensUpdated 21 days ago
    Auto-check passed
  • n8n Multi-Instance Targeting

    czlonkowski/n8n-skills

    Keeps an n8n MCP session pointed at the right n8n instance, with rules for discovering, switching and verifying the target before credential writes and for recovering from misroutes.

    6.4k GitHub stars~3.2k tokensUpdated 21 days ago
    Auto-check passed
  • n8n Node Configuration

    czlonkowski/n8n-skills

    Explains how to configure n8n nodes correctly: which fields each operation requires, how property dependencies show or hide fields, and which get_node detail level to use.

    6.4k GitHub stars~4.5k tokensUpdated 21 days ago
    Auto-check passed

Questions about Native Python in n8n Code Nodes

What does Native Python in n8n Code Nodes do?

Explains how to write native Python in n8n Code nodes, including the two input variables, blocked imports and fixes for common errors. 0, Python in the Code node runs as native Python in a task runner, with `language` set to `pythonNative`. The old Pyodide 'Python (Beta)' and its helpers such as `_input`, `_json`, `_node` and `_now` are gone and now raise `NameError`, which is why code copied from older templates often breaks.

When should I use Native Python in n8n Code Nodes?

Native Python in n8n Code Nodes fits situations like: writing Python in an n8n Code node when you explicitly want Python; migrating old Pyodide Python code that used _input or _json; fixing a Code node that fails with NameError or a security violation.

How do I install Native Python in n8n Code Nodes in Claude Code?

Run `npx skills add czlonkowski/n8n-skills --skill n8n-code-python -a claude-code`. Or copy the skill folder (skills/n8n-code-python in czlonkowski/n8n-skills) into .claude/skills/n8n-code-python in your project. Claude Code loads it when a task matches its description.

How do I install Native Python in n8n Code Nodes in Codex?

Run `npx skills add czlonkowski/n8n-skills --skill n8n-code-python -a codex`. Or copy the skill folder (skills/n8n-code-python in czlonkowski/n8n-skills) into .agents/skills/n8n-code-python in your project. Codex loads it when a task matches its description.

Can I use Native Python in n8n Code Nodes in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add czlonkowski/n8n-skills --skill n8n-code-python -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/n8n-code-python, .gemini/skills/n8n-code-python, .github/skills/n8n-code-python and .opencode/skills/n8n-code-python in your project.

What does Native Python in n8n Code Nodes need to run?

Going by SKILL.md and its folder, Native Python in n8n Code Nodes needs the command-line tools its instructions call (python). Our summary lists: n8n 2.x with the native Python task runner.

Does Native Python in n8n Code Nodes access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Native Python in n8n Code Nodes safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Native Python in n8n Code Nodes use?

Native Python in n8n Code Nodes is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Native Python in n8n Code Nodes use?

About 2.8k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Native Python in n8n Code Nodes?

Skills that share tags, products or a category with Native Python in n8n Code Nodes: N8n Code Python (davila7/claude-code-templates, 32k stars), N8n Code Tool (sickn33/agentic-awesome-skills, 47k stars), N8n Code Javascript (davila7/claude-code-templates, 32k stars) and VectCutAPI Video Editing (sun-guannan/VectCutAPI, 2.3k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Native Python in n8n Code Nodes?

czlonkowski (a GitHub user) maintains it in czlonkowski/n8n-skills, which has 6,387 GitHub stars. The repository holds 15 skills in this directory. The repository was last updated on September 16, 2026.

Source: czlonkowski/n8n-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.