Python Code Node (Beta)
Expert guidance for writing Python code in n8n Code nodes.
When to use
- Writing or reviewing a Python Code node in n8n.
- Using
_input / _json / _node syntax.
- Selecting between Python (Beta) and Python (Native).
- Understanding what is and is not available in the n8n Python runtime.
- Switching between Python and JavaScript Code nodes.
- Debugging
ModuleNotFoundError, KeyError, or empty-output issues.
Required input contract
Before writing or reviewing a Python Code node, identify:
- Mode — "Run Once for All Items" (default, 95% of cases) vs "Run Once for Each Item".
- Runtime — Python (Beta, recommended) vs Python (Native, Beta).
- Upstream node(s) — which provides the input; webhook, HTTP, manual, or another Code node.
- Required output cardinality — single, list, empty, or filtered.
- Reason for Python over JavaScript — Python is justified only by stdlib needs, comfort, or list-comprehension fit.
JavaScript first
Use JavaScript for 95% of use cases. Choose Python only when:
- You need a specific stdlib module (e.g.,
statistics).
- You are significantly more comfortable in Python.
- The transform maps cleanly to Python idioms.
JavaScript advantages: full $helpers (incl. $helpers.httpRequest()), Luxon
DateTime, no external-library limit, better n8n documentation.
n8n Python Code node constraints
These constraints apply to every Python Code node and must always be respected.
- No external libraries.
requests, pandas, numpy, bs4, lxml,
httpx, etc. produce ModuleNotFoundError. Standard library only.
- Available stdlib:
json, datetime, re, base64, hashlib,
urllib.parse, math, random, statistics.
- Return shape: every code path returns a list of dicts each with a
"json" key. Single returns are wrapped in a list. Empty result is return [].
- Webhook data nests under
["body"]. Use _json.get("body", {}).get(...).
- Dictionary access uses
.get() — fields may be missing.
- HTTP requests cannot originate inside the Code node. Use the HTTP Request
node upstream, or switch to JavaScript.
- Beta and Native runtimes have different variables (
_input/_json/_node
vs _items/_item). Do not mix them.
Workflow (compact)
- Language: JavaScript first; Python only when justified.
- Mode: All Items (default) vs Each Item.
- Runtime: Beta (recommended) vs Native.
- Read:
_input.all() / .first() / .item / _node["..."]["json"].
- Transform: stdlib only; list comprehensions preferred.
- Return:
[{"json": {...}}, ...] on every code path.
- Validate: walk the validation-gates checklist (below).
Full workflow + mode and runtime examples: references/python-code-workflow.md.
Decision logic
Mode selection
| Mode |
When |
Data access |
| Run Once for All Items (default, 95%) |
Aggregation, filtering, batch |
_input.all() |
| Run Once for Each Item |
Item-specific logic, independent ops |
_input.item |
Runtime selection
| Runtime |
Variables |
Helpers |
| Python (Beta) — recommended |
_input, _json, _node |
_now, _today, _jmespath() |
| Python (Native, Beta) |
_items, _item only |
None |
Data access
| Accessor |
When |
_input.all() |
Arrays, batches, aggregations |
_input.first() |
Single objects, API responses |
_input.item |
Each-Item mode only |
_node["Name"]["json"] |
Reference a non-immediate upstream node |
Python vs JavaScript
| Situation |
Use |
| HTTP request inside the node |
JavaScript |
| Advanced date/time (Luxon, timezones) |
JavaScript |
Python statistics module |
Python |
| Simple field mapping |
Use Set node instead |
| Basic filtering |
Use Filter node instead |
| Conditional routing |
Use IF / Switch node instead |
Minimal critical examples
Quick Start
from datetime import datetime
items = _input.all()
return [
{"json": {**it["json"], "processed": True, "ts": datetime.now().isoformat()}}
for it in items
]
Webhook field access
data = _json.get("body", {})
name = data.get("name", "")
return [{"json": {"name": name.strip()}}]
Return-format right/wrong
return [{"json": {"id": 1}}] # RIGHT — single item
return [{"json": {"id": 1}}, {"json": {"id": 2}}] # RIGHT — multiple
return [] # RIGHT — empty
return {"json": {"id": 1}} # WRONG — dict not wrapped
return [{"id": 1}] # WRONG — missing "json" key
Worked end-to-end examples (webhook, aggregation, multi-node merge, regex
extract, checksum, per-item conditional): references/examples.md.
Validation gates
Before deploying a Python Code node:
Full top-5-mistakes catalog, best practices, debugging playbook, anti-patterns:
references/validation-troubleshooting-and-antipatterns.md.
Output expectations
When delivering a Python Code node:
- Provide the full code block, ready to paste into the Code node.
- State the mode (All Items / Each Item) and runtime (Beta / Native).
- Note any required upstream nodes (HTTP Request, Webhook, etc.).
- List required stdlib imports at the top.
- Flag any branch that returns
[] and what that means downstream.
Integration with other skills
- n8n Expression Syntax — expressions use
{{ }} in other nodes; Code
nodes use Python directly, no {{ }}.
- n8n MCP Tools Expert — find Code node via
search_nodes({query: "code"});
configure via get_node({nodeType: "nodes-base.code"}); validate via
validate_node({nodeType: "nodes-base.code", config: {...}}).
- n8n Node Configuration — mode and language selection are node properties.
- n8n Validation Expert — interpret validation errors, auto-fix issues.
- n8n Code JavaScript — when to switch; feature comparison.
Reference map
| Need |
Read |
| Mode + runtime + return-format full examples; workflow steps |
references/python-code-workflow.md |
| Data access patterns, webhook body, 5 production transform/filter/validate/stats patterns, stdlib quick reference |
references/item-and-data-patterns.md |
| HTTP request strategy, auth, scraping, multiple-request orchestration, decision table |
references/api-requests-and-integrations.md |
| Top 5 mistakes, best practices, no-library workarounds, debugging playbook, validation gates, anti-patterns |
references/validation-troubleshooting-and-antipatterns.md |
| End-to-end worked examples (webhook, aggregation, multi-node merge, regex, checksum, per-item conditional) |
references/examples.md |
| Upstream comprehensive depth |
references/common-patterns.md, references/data-access.md, references/error-patterns.md, references/standard-library.md |
1---2name: n8n-code-python3description: Write Python code in n8n Code nodes. Use when writing Python in n8n, using _input/_json/_node syntax, working with standard library, or need to understand Python limitations in n8n Code nodes.4---56# Python Code Node (Beta)78Expert guidance for writing Python code in n8n Code nodes.910## When to use1112- Writing or reviewing a Python Code node in n8n.13- Using `_input` / `_json` / `_node` syntax.14- Selecting between Python (Beta) and Python (Native).15- Understanding what is and is not available in the n8n Python runtime.16- Switching between Python and JavaScript Code nodes.17- Debugging `ModuleNotFoundError`, `KeyError`, or empty-output issues.1819## Required input contract2021Before writing or reviewing a Python Code node, identify:2223- **Mode** — "Run Once for All Items" (default, 95% of cases) vs "Run Once for Each Item".24- **Runtime** — Python (Beta, recommended) vs Python (Native, Beta).25- **Upstream node(s)** — which provides the input; webhook, HTTP, manual, or another Code node.26- **Required output cardinality** — single, list, empty, or filtered.27- **Reason for Python over JavaScript** — Python is justified only by stdlib needs, comfort, or list-comprehension fit.2829## JavaScript first3031Use **JavaScript for 95% of use cases**. Choose Python only when:3233- You need a specific stdlib module (e.g., `statistics`).34- You are significantly more comfortable in Python.35- The transform maps cleanly to Python idioms.3637JavaScript advantages: full `$helpers` (incl. `$helpers.httpRequest()`), Luxon38DateTime, no external-library limit, better n8n documentation.3940## n8n Python Code node constraints4142These constraints apply to every Python Code node and must always be respected.43441. **No external libraries.** `requests`, `pandas`, `numpy`, `bs4`, `lxml`,45 `httpx`, etc. produce `ModuleNotFoundError`. Standard library only.462. **Available stdlib**: `json`, `datetime`, `re`, `base64`, `hashlib`,47 `urllib.parse`, `math`, `random`, `statistics`.483. **Return shape**: every code path returns a list of dicts each with a49 `"json"` key. Single returns are wrapped in a list. Empty result is `return []`.504. **Webhook data nests under `["body"]`**. Use `_json.get("body", {}).get(...)`.515. **Dictionary access uses `.get()`** — fields may be missing.526. **HTTP requests cannot originate inside the Code node.** Use the HTTP Request53 node upstream, or switch to JavaScript.547. **Beta and Native runtimes have different variables** (`_input`/`_json`/`_node`55 vs `_items`/`_item`). Do not mix them.5657## Workflow (compact)58591. **Language**: JavaScript first; Python only when justified.602. **Mode**: All Items (default) vs Each Item.613. **Runtime**: Beta (recommended) vs Native.624. **Read**: `_input.all()` / `.first()` / `.item` / `_node["..."]["json"]`.635. **Transform**: stdlib only; list comprehensions preferred.646. **Return**: `[{"json": {...}}, ...]` on every code path.657. **Validate**: walk the validation-gates checklist (below).6667Full workflow + mode and runtime examples: `references/python-code-workflow.md`.6869## Decision logic7071### Mode selection7273| Mode | When | Data access |74|------|------|-------------|75| Run Once for All Items (default, 95%) | Aggregation, filtering, batch | `_input.all()` |76| Run Once for Each Item | Item-specific logic, independent ops | `_input.item` |7778### Runtime selection7980| Runtime | Variables | Helpers |81|---------|-----------|---------|82| Python (Beta) — recommended | `_input`, `_json`, `_node` | `_now`, `_today`, `_jmespath()` |83| Python (Native, Beta) | `_items`, `_item` only | None |8485### Data access8687| Accessor | When |88|----------|------|89| `_input.all()` | Arrays, batches, aggregations |90| `_input.first()` | Single objects, API responses |91| `_input.item` | Each-Item mode only |92| `_node["Name"]["json"]` | Reference a non-immediate upstream node |9394### Python vs JavaScript9596| Situation | Use |97|-----------|-----|98| HTTP request inside the node | JavaScript |99| Advanced date/time (Luxon, timezones) | JavaScript |100| Python `statistics` module | Python |101| Simple field mapping | Use **Set** node instead |102| Basic filtering | Use **Filter** node instead |103| Conditional routing | Use **IF** / **Switch** node instead |104105## Minimal critical examples106107### Quick Start108109```python110from datetime import datetime111112items = _input.all()113return [114 {"json": {**it["json"], "processed": True, "ts": datetime.now().isoformat()}}115 for it in items116]117```118119### Webhook field access120121```python122data = _json.get("body", {})123name = data.get("name", "")124return [{"json": {"name": name.strip()}}]125```126127### Return-format right/wrong128129```python130return [{"json": {"id": 1}}] # RIGHT — single item131return [{"json": {"id": 1}}, {"json": {"id": 2}}] # RIGHT — multiple132return [] # RIGHT — empty133return {"json": {"id": 1}} # WRONG — dict not wrapped134return [{"id": 1}] # WRONG — missing "json" key135```136137Worked end-to-end examples (webhook, aggregation, multi-node merge, regex138extract, checksum, per-item conditional): `references/examples.md`.139140## Validation gates141142Before deploying a Python Code node:143144- [ ] Considered JavaScript first — Python is the right choice.145- [ ] Code is not empty.146- [ ] Final `return` statement exists.147- [ ] Return shape is `[{"json": {...}}, ...]` on every code path.148- [ ] Data access uses only `_input.all()` / `_input.first()` / `_input.item` /149 `_node["..."]["json"]`.150- [ ] No external library imports — stdlib only.151- [ ] `.get(key, default)` everywhere for dictionary access.152- [ ] Webhook data accessed via `_json.get("body", {})`.153- [ ] Mode is "All Items" unless per-item independence is required.154- [ ] Output is consistent across every branch and exception path.155156Full top-5-mistakes catalog, best practices, debugging playbook, anti-patterns:157`references/validation-troubleshooting-and-antipatterns.md`.158159## Output expectations160161When delivering a Python Code node:162163- Provide the full code block, ready to paste into the Code node.164- State the mode (All Items / Each Item) and runtime (Beta / Native).165- Note any required upstream nodes (HTTP Request, Webhook, etc.).166- List required stdlib imports at the top.167- Flag any branch that returns `[]` and what that means downstream.168169## Integration with other skills170171- **n8n Expression Syntax** — expressions use `{{ }}` in other nodes; Code172 nodes use Python directly, no `{{ }}`.173- **n8n MCP Tools Expert** — find Code node via `search_nodes({query: "code"})`;174 configure via `get_node({nodeType: "nodes-base.code"})`; validate via175 `validate_node({nodeType: "nodes-base.code", config: {...}})`.176- **n8n Node Configuration** — mode and language selection are node properties.177- **n8n Validation Expert** — interpret validation errors, auto-fix issues.178- **n8n Code JavaScript** — when to switch; feature comparison.179180## Reference map181182| Need | Read |183|------|------|184| Mode + runtime + return-format full examples; workflow steps | `references/python-code-workflow.md` |185| Data access patterns, webhook body, 5 production transform/filter/validate/stats patterns, stdlib quick reference | `references/item-and-data-patterns.md` |186| HTTP request strategy, auth, scraping, multiple-request orchestration, decision table | `references/api-requests-and-integrations.md` |187| Top 5 mistakes, best practices, no-library workarounds, debugging playbook, validation gates, anti-patterns | `references/validation-troubleshooting-and-antipatterns.md` |188| End-to-end worked examples (webhook, aggregation, multi-node merge, regex, checksum, per-item conditional) | `references/examples.md` |189| Upstream comprehensive depth | `references/common-patterns.md`, `references/data-access.md`, `references/error-patterns.md`, `references/standard-library.md` |