Python in n8n changed significantly. The first implementation ran Python through Pyodide, a WebAssembly port of CPython. n8n then introduced native Python on task runners, available from version 1.111.0 and stable as of n8n 2. Pyodide is removed in n8n 2.0. If your old Python snippets now fail, this is why. Here is how the current version works.
In short. In native Python you read data with _items (Run Once for All Items) or _item (Run Once for Each Item), using bracket notation: item["json"]["email"]. Other n8n helpers such as _input or _now are not supported in native Python. Imports are blocked by default: allow them with N8N_RUNNERS_STDLIB_ALLOW and N8N_RUNNERS_EXTERNAL_ALLOW on self-hosted. On n8n Cloud you cannot import any library.
What changed from Pyodide to native Python
According to the n8n documentation, the main differences are:
| Topic | Pyodide (legacy) | Native Python (current) |
|---|---|---|
| Availability | Removed in n8n 2.0 | From 1.111.0, stable in n8n 2 |
| Data access | Many _ helpers, dot notation | Only _items and _item, bracket notation |
| Libraries | Packages bundled with Pyodide | Standard library and third-party, if allowed and installed (self-hosted) |
| Insecure built-ins | Allowed | Denied by default |
| Speed | Slower than JavaScript | Runs in a real Python process |
Upgrading is a breaking change, so plan to rewrite snippets that used dot access such as item.json.myField.
The syntax that works
Run Once for All Items
Run Once for Each Item
The return format is the same as in JavaScript: a list of dictionaries, each with a "json" key holding a dictionary.
Allowing imports on self-hosted n8n
By default native Python blocks all imports, even json or datetime from the standard library. Two variables open them:
| Variable | What it allows |
|---|---|
N8N_RUNNERS_STDLIB_ALLOW | Standard library modules, for example json,datetime,re, or * |
N8N_RUNNERS_EXTERNAL_ALLOW | Third-party modules, for example pandas, or * |
Third-party packages must also exist in the runner image (n8nio/runners in the official setup). The documentation describes adding extra dependencies by extending that image. In external mode, set these variables in the runners configuration, not on the main n8n container.
n8n Cloud
On n8n Cloud the Python option of the Code node does not allow importing any library, from the standard library or third parties. Plain Python works; import does not. If you need a library on Cloud, use JavaScript (which has crypto and moment), a dedicated n8n node, or call an external function with the HTTP Request node.
Python or JavaScript?
Choose JavaScript when:
- you need n8n helpers such as
$('Node name'),$execution,$nowor binary data functions, which native Python does not support; - you are on n8n Cloud and need any library;
- the next person maintaining the workflow does not read Python.
Choose Python when the logic itself is easier in Python (text processing, data science libraries you are allowed to install) and the input arrives through the node's own items.
Worked example: migrate a Pyodide snippet to native Python
Many workflows built in 2023 and 2024 contain snippets like this one, which stopped working when Pyodide was removed:
The native version, for "Run Once for All Items":
What changed, line by line:
-
_input.all()became_items; -
item.json.emailbecameitem["json"]["email"], read safely with.get(); - the item is rebuilt as a dictionary with a
"json"key before returning; - the domain split is guarded, because native Python raises an error on a missing
@just like the old code did, but now you see it instead of a vague failure.
Allowing libraries on self-hosted n8n
Three steps, in this order:
- 1 Install third-party packages in the runner image (the official runner image is
n8nio/runners), by extending it as the n8n documentation describes. - 2 Allow them: standard-library modules in
N8N_RUNNERS_STDLIB_ALLOW, third-party modules inN8N_RUNNERS_EXTERNAL_ALLOW. Use names, not*, unless the instance is single-user. - 3 Restart the runners.
There is also N8N_RUNNERS_ALLOW_TRANSITIVE_IMPORTS: by default, imports made inside an allowed package must be allowed too. Turning it on lets an allowed package load its own dependencies, at the cost of a wider surface.
When native Python is the right tool
| Job | Python fit |
|---|---|
| Text cleanup with regular expressions | Good, with re allowed |
| Statistics on a list of numbers | Good, with statistics allowed |
| Heavy data work (pandas) on self-hosted | Possible if installed and allowed in the runner |
Reading other nodes, $now, execution data | Not supported in native Python: use JavaScript |
| Files and binary data | Not supported: use JavaScript or file nodes |
| n8n Cloud with any import | Not possible |
Troubleshooting table
| Symptom | Likely cause | Fix |
|---|---|---|
NameError: _input is not defined | Pyodide-era helper | Use _items or _item |
AttributeError: 'dict' object has no attribute 'json' | Dot notation | Use item["json"] |
| Import blocked | Module not in the allow list | Add it to N8N_RUNNERS_STDLIB_ALLOW or _EXTERNAL_ALLOW |
ModuleNotFoundError for a third-party package | Not installed in the runner image | Extend the runner image |
| Any import on n8n Cloud | Not supported | Use plain Python or JavaScript |
| Script stopped after a few minutes | Runner task timeout (300 s by default) | Split the work or raise N8N_RUNNERS_TASK_TIMEOUT |
Production checklist
- n8n version checked: native Python, not Pyodide, from n8n 2.0.
- Bracket notation everywhere (
item["json"]["field"]). - Imports allowed explicitly and installed in the runner image (self-hosted).
- JavaScript chosen instead when you need n8n helpers or Cloud libraries.
Frequently asked questions
Why did my Python Code node break after upgrading n8n?
n8n 2.0 removed Pyodide. Native Python uses bracket notation (item["json"]["field"]) and only supports _items and _item. Rewrite dot access and remove other _ helpers.
How do I import a Python library in n8n?
On self-hosted n8n, list it in N8N_RUNNERS_STDLIB_ALLOW (standard library) or N8N_RUNNERS_EXTERNAL_ALLOW (third-party), and make sure third-party packages are installed in the runner image. On n8n Cloud, imports are not allowed.
Can I read binary files with Python in n8n?
The getBinaryDataBuffer() helper is not supported in Python. Use JavaScript or the Extract from File node for that step.
Is Python slower than JavaScript in n8n?
The old Pyodide version was noticeably slower. Native Python runs in a real Python process on task runners. For typical workflow volumes either language is fast enough; pick the one your team maintains best.
Is Python faster or slower than JavaScript in n8n?
For typical workflow volumes both are fast. JavaScript has the advantage of n8n's built-in helpers; Python is worth it when the logic or library is genuinely better in Python.
Can I use pandas in n8n?
On self-hosted n8n with native Python, if pandas is installed in the runner image and allowed with N8N_RUNNERS_EXTERNAL_ALLOW. Not on n8n Cloud.
Which n8n version do I need for native Python?
Native Python on task runners is available from n8n 1.111.0 and stable as of n8n 2. Pyodide is removed from n8n 2.0.
Tags
Steve founded PURIST, a workflow automation studio working with n8n, Make and Claude AI, and is the point of contact on every project. Prices and features in our articles come from vendor documentation and public pricing pages. How we research and score tools.