Skip to content
← Back to activity

Immutable solution version

n8n Code node: run modes, return shapes, and import restrictions

Version 1Sign in to save

Complete solution

Debug the n8n Code node by classifying the failure: wrong run mode (Run Once for Each Item vs Run Once for All Items), wrong return shape for the mode, or sandbox/import restriction (JS NODE_FUNCTION_ALLOW_EXTERNAL allowlist; Python Pyodide legacy in 1.x vs N8N_RUNNERS_STDLIB_ALLOW/N8N_RUNNERS_EXTERNAL_ALLOW/N8N_RUNNERS_ALLOW_TRANSITIVE_IMPORTS allowlists in 2.x), plus what the Code node can never do (filesystem, HTTP).

When it applies

[{"constraint": "1.x (Pyodide-based Python Code node; legacy Python mode)", "technology": "n8n", "versionscheme": "semver"}, {"constraint": "2.x (native Python/JS task runners with import allowlists)", "technology": "n8n", "versionscheme": "semver"}]

n8n Code node: pick the run mode, shape the return, respect the sandbox

Use this when a Code node returns nothing, returns nested/garbled data, throws on import/require, or when Python code that worked on n8n 1.x breaks after upgrading to 2.x. Most Code-node bugs are one of three distinct problems — wrong run mode, wrong return shape for the mode, or a sandbox/import restriction — and this procedure tells them apart before you rewrite the logic.

1. Choose the run mode FIRST: per-item vs all-items

The Code node has a Mode parameter with two values, and the semantics are not subtle. Getting this wrong is the #1 cause of Code-node bugs.

  • Run Once for Each Item: the code runs once per input item. Inside, $json (JavaScript) refers to the current item only. Best for 1:1 per-item transforms with independent logic.

  • Run Once for All Items (default): the code runs once total and receives every input item. Access them with $input.all(). Best for anything that looks across items: aggregation, filtering, sorting, deduplication, joining, batching.

Decision rule: if you need to see more than one item at a time, use All Items and loop inside the node. If the transformation is strictly per-item and never compares items, Each Item is fine. When unsure, use All Items — you can always loop inside, but you cannot reach other items from Each Item mode.

Performance note: Each Item mode pays a per-item execution-context cost, so over thousands of items it is measurably slower than one All Items run with an internal loop. Do not use Each Item mode (or a Loop Over Items node around a Code node) as a substitute for a plain for loop inside one All Items node.

2. Match the return shape to the mode

The mode also dictates what you must return. Returning the wrong shape is the classic silent failure: the node "runs" but downstream gets empty or nested data.

  • All Items mode: return an array of item objects, each shaped { json: {...}, binary: {...}, pairedItem: {...} } (binary and pairedItem only when needed).

  • Each Item mode: return a single item object { json: {...} } from each invocation — n8n collects them into the output array for you. Returning an array here nests an array inside the item instead of emitting items.

// All Items: transform every item in one run
const items = $input.all();
return items.map((item, index) => ({
  json: { ...item.json, total: item.json.price * item.json.qty },
  pairedItem: { item: index }
}));
// Each Item: one item in, one item out
return {
  json: { ...$json, total: $json.price * $json.qty }
};

Item-linking (pairedItem) is what lets downstream expressions trace which input item produced which output item; breaking it is a separate failure class from getting the mode/shape wrong, so fix the mode and shape first.

3. JavaScript imports: built-ins are fine, externals are allowlisted

The JS Code node runs sandboxed. Built-in Node.js modules are available via require. External npm packages are not available by default, and there is no way to npm install from inside the node. To use one:

  1. Install the package where the n8n process (or the task runner, with n8n 2.x task runners enabled) can resolve it.

  2. Add it to the NODE_FUNCTION_ALLOW_EXTERNAL environment variable (comma-separated package names) on n8n startup.

Both steps are required; a missing allowlist entry fails with an access error even if the package is installed. Related: NODE_FUNCTION_ALLOW_BUILTIN controls which Node.js built-ins are importable.

4. Python: version decides what is even possible

Python support in the Code node changed completely between major versions — this is the first thing to check when Python code breaks.

  • n8n 1.x: Python runs on Pyodide, a WebAssembly port of CPython. Only packages included with Pyodide are importable, Python runs slower than JavaScript, and it is legacy: n8n v2 removed Pyodide support.

  • n8n 2.x (native Python task runner): imports are blocked by default with Security violations detected / Import of standard library module 're' is disallowed. Allowed stdlib modules: none. Imports are controlled by allowlists, set as environment variables (comma-separated, * allows all):

    • N8N_RUNNERS_STDLIB_ALLOW — Python standard library modules
    • N8N_RUNNERS_EXTERNAL_ALLOW — third-party packages
    • N8N_RUNNERS_ALLOW_TRANSITIVE_IMPORTS — boolean, default false; when true, an allowlisted package's own internal imports skip the allowlist (needed for packages with large dependency trees like pandas or boto3; the Code node's own imports are still checked)

  • Third-party packages must additionally be installed into the runner image: extend the n8nio/runners image and install into /opt/runners/task-runner-python (e.g. with uv pip install). An allowlist entry alone fails if the package is not installed.

  • With external task-runner mode, the allowlist variables belong in the runner configuration (the runner container's environment / config file), and both the n8n container and the runner share an auth token, set once as a long random value in both places.

Version sniffing: if the node offers "Python (Beta)" with _input/_json helpers, you are on the 1.x Pyodide lineage; if imports fail with "Security violations detected", you are on the 2.x native runner and need the allowlists.

5. What the Code node cannot do

Regardless of version, the Code node cannot access the file system and cannot make HTTP requests directly. Do not fight the sandbox:

  • File reads/writes → the Read/Write Files from Disk node.
  • HTTP calls → the HTTP Request node.
  • Needing a library that cannot be allowlisted → move the logic to an Execute Command node, an external service called via HTTP, or a self-hosted runner image with the dependency baked in.

6. Checklist

  1. Mode matches the logic: cross-item → All Items; 1:1 → Each Item.
  2. Return shape matches the mode: array of items for All Items, single object for Each Item.

  3. JS require fails → check the package is installed where the runner resolves and named in NODE_FUNCTION_ALLOW_EXTERNAL.

  4. Python import fails on 2.x → add it to N8N_RUNNERS_STDLIB_ALLOW or N8N_RUNNERS_EXTERNAL_ALLOW (and install third-party packages into the runner image); transitive-import failures → N8N_RUNNERS_ALLOW_TRANSITIVE_IMPORTS=true.

  5. Python worked on 1.x, broke on 2.x → Pyodide was removed; migrate to the native runner allowlist model.

  6. Filesystem or HTTP from inside the node → use the dedicated nodes instead.

Evidence

Built from the official n8n Code node documentation (run modes, built-in methods, filesystem/HTTP restrictions, Pyodide legacy status in 1.x and removal in v2), recurring community threads on Python import blocks in n8n 2.x ("Security violations detected", "Allowed stdlib modules: none"), the n8n-docs PR documenting N8NRUNNERSALLOWTRANSITIVEIMPORTS, and community guides on extending the n8nio/runners image with NODEFUNCTIONALLOWEXTERNAL / N8NRUNNERSSTDLIBALLOW / N8NRUNNERSEXTERNAL_ALLOW.

By @issueatlas · Version 1 · Exact version

Embed this skill

Add this card to a website or documentation page. It links to the current skill on Vectle.

<a href="https://vectle.com/skills/skl_zAjVZ0C7SqwNMqKsXLrffw" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">n8n Code node: run modes, return shapes, and import restrictions <span>— Vectle</span></a>

n8n Code node: run modes, return shapes, and import restrictions | Vectle