Code (core.code)
Real Python when field mapping isn't enough. Your code runs in an isolated subprocess, receives the incoming items, and whatever list you return becomes the node's output.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | run_once_all_items | run_per_item | run_once_all_items | Run once with the whole list, or once per item. |
code | Python | return items | The function body. In run_once_all_items you get items (a list); in run_per_item you get item. Each item is {"json": {...}}. |
Writing code
# run_once_all_items — items is the full list
total = sum(i["json"]["amount"] for i in items)
return [{"json": {"total": total}}]
# run_per_item — item is one item; return its replacement
return {"json": {**item["json"], "flagged": item["json"]["amount"] > 100}}
Return shapes are forgiving. Return full items ({"json": {...}}),
plain dicts (they become the json), or scalars (they land under "value").
run_once_all_items must return a list; anything else is a clean error.
Imports come from an allowlist: json, re, math, datetime,
itertools, collections, statistics out of the box, plus whatever your
admin enabled under Settings → Code imports (any module installed in the
backend image — pandas, requests, … — no rebuild needed). A disallowed
import fails fast with a clear message, before anything runs.
print() is safe — debug output goes to the worker log, never into your
results.
Drag to map: dragging a field from the input pane into the code editor
inserts a real Python subscript (item["json"]["email"]), not a template.
Limits
The subprocess gets ~10s of CPU, a best-effort 256 MB memory cap, and a 30s
wall clock — a runaway loop kills the node, not the worker. Dangerous
builtins (open, eval, exec, dunder access, …) are rejected by a static
check before execution. This is process-level isolation, not a security
boundary against a hostile operator.
Shared/demo instances may disable the Code node entirely. Because the sandbox is process-level (not a hardened boundary), an operator running an open/demo instance can lock the node off: the palette greys it out and any run that reaches it fails with "the Code node is disabled on this instance." Self-hosted instances ship with it enabled — you trust your own authors.
Quirks & tips
{{ }}is never expanded in code. The code field is the one parameter that's deliberately not templated —"{{ $json.x }}"reaches Python as literal text. Read data fromitem/itemsinstead.- Binary attachments do not pass through. The subprocess sees json only; output items carry no binary. Put the Code node before the attachment step, or route files around it on a parallel branch.
- Imported n8n JavaScript arrives as a stub with your original JS in comments — the editor's banner offers a one-click AI translation to Python; review it before enabling the node.
- Exceptions in your code fail the node with
Type: message— the run's error names this node, and already-emitted upstream data is unaffected. - Mutating
itemsin place is fine: the subprocess works on a copy, so upstream recorded data never changes under you.
Related
- Set — for simple field writes, no code needed.
- HTTP Request — call APIs natively instead of scripting them.
- Execute Workflow — split heavy logic into a sub-workflow.