core.code

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

ParameterTypeDefaultDescription
moderun_once_all_items | run_per_itemrun_once_all_itemsRun once with the whole list, or once per item.
codePythonreturn itemsThe 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 from item/items instead.
  • 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 items in 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.