FlowKit

Native Python in n8n: installing pandas and numpy with the Task Runner

By Clément Lacaille (Tech-Bharat) · Published 21 September 2026 · 4 min read · how we build and test

RAG Assistant Pack — €119

4 ready-to-import n8n workflows, setup guide in French, 14-day guarantee

See the pack

The Python (Beta) option in the Code node runs on Pyodide, a distribution of CPython compiled to WebAssembly: convenient because it needs no installation, but closed off from pandas, numpy, or any third-party package that isn't pre-bundled for it. Since n8n 1.111, a second path exists for self-hosted instances: a native Python runner, which executes a real CPython interpreter in its own process, with actual access to pip and PyPI. This guide covers how to enable it, how to install data-science libraries in it, and where its advantages over Pyodide stop.

Two Pythons, not one

It's easy to conflate the two options since they share the same selector in the Code node. The difference is fundamental, though:

Python (Beta) — Pyodide Native Python — Task Runner
Engine CPython compiled to WebAssembly Native CPython, separate process
Third-party packages Closed list precompiled for Pyodide Any PyPI package, if installed and allowlisted
Available on n8n Cloud Yes No
Setup required None Custom Docker image + environment variables
Isolation WebAssembly sandbox, inside the n8n process Dedicated Task Runner process, ideally in external mode

The native runner doesn't replace Pyodide, then: it opens an additional option for self-hosted setups, at the cost of some infrastructure configuration. If your code doesn't depend on any external package, Pyodide remains the simplest choice — it works identically on Cloud and self-hosted, with no Docker image to maintain.

Enabling the native runner

On the main n8n instance, a single variable is enough to switch the Code node to native mode for Python executions:

N8N_NATIVE_PYTHON_RUNNER=true

This variable applies to the n8n instance itself (not the runner container). Flipping this on an environment that already has Python scripts running in production isn't a neutral addition, it's a behavior change: the new executor doesn't necessarily reproduce every quirk of Pyodide identically. Enable it first on a staging environment, run your existing Python workflows against it, and switch only one environment at a time.

Installing pandas, numpy and more with uv

The official n8nio/runners image bundles uv, a much faster drop-in replacement for pip, already present in the Python runner's environment. To add packages, you build an image that extends the official one rather than installing on the fly in an ephemeral container:

FROM n8nio/runners:1.121.0
USER root
RUN cd /opt/runners/task-runner-python && uv pip install pandas numpy

Two things matter here:

  • The n8nio/runners image tag must match the version of n8nio/n8n your instance runs. A version mismatch between the main instance and the runner is a classic source of hard-to-diagnose errors.
  • Install into a versioned image, not into a running container. A one-off docker exec to add a package doesn't survive a redeploy without a dedicated volume; a custom image reproduces the same environment identically on every deploy instead — the same principle already recommended for adding npm modules to the JavaScript Code node.

The mandatory allowlist: N8N_RUNNERS_EXTERNAL_ALLOW

Installing a package in the image isn't enough to make it importable: it also has to be explicitly authorized, package by package, through a variable set on the runner container:

N8N_RUNNERS_EXTERNAL_ALLOW=pandas,numpy

This comma-separated allowlist isn't a gratuitous restriction. It answers a documented problem in the PyPI ecosystem itself: a study by Neupane, Holmes, Wyss, Davidson, and De Carli, published at the USENIX Security Symposium 2023, catalogs more than 1,200 real-world "package confusion" attacks — typosquatting, but also far subtler mechanisms than a simple typo — that led developers to unknowingly install a malicious package instead of the intended one. On an n8n instance that runs business workflows and handles credentials, forcing an explicit allowlist instead of a free-for-all import mechanically limits the attack surface: even a package installed by mistake, or compromised after the fact, stays unusable until it's been added to the list by hand, by whoever administers the instance.

A concrete use case: cleaning data before indexing it

The native runner earns its place on data-prep steps too heavy for n8n's usual IF/Set nodes. A typical example: before feeding a RAG pipeline like the one in the RAG Assistant Pack, a native Python Code node can deduplicate near-identical rows with pandas, normalize numeric columns with numpy, or filter a large CSV export before passing it to the PDF-to-Supabase-pgvector ingestion workflow. That kind of tabular processing, tedious to write in plain JavaScript, becomes a handful of idiomatic lines once pandas is genuinely available — which wasn't the case with Pyodide.

What stays the same on n8n Cloud

None of this applies to n8n Cloud. The Python option in the Code node stays deliberately closed there: no extended standard library, no third-party package, for a simple reason — Cloud doesn't let you build a custom Docker image for the runner. If your data-processing needs outgrow what Pyodide allows and you're on Cloud, the only route remains an external microservice called via HTTP Request, as covered in the Python and Pyodide guide. The native runner is, by construction, a self-hosted advantage.

Summary

The native Python runner doesn't make Pyodide obsolete: it adds an option for cases that genuinely need a real PyPI library, reserved for self-hosted instances willing to maintain a dedicated Docker image. The checklist comes down to four points: N8N_NATIVE_PYTHON_RUNNER=true on the instance, an image extending n8nio/runners with uv pip install, an image version aligned with n8n's, and an N8N_RUNNERS_EXTERNAL_ALLOW that lists only what's actually needed. Everything else — Pyodide, or an external microservice — still covers every other case, Cloud included.

FAQ

Frequently asked questions

Does native Python replace the Python (Beta) option in the Code node?

No, both coexist. The historical Python (Beta) still runs on Pyodide, including on n8n Cloud. The native runner is an additional option, opt-in and self-hosted only, that runs real CPython in a separate Task Runner. Switching to it is a behavior change: test your existing scripts before enabling it on a production instance.

Can you use pandas and numpy on n8n Cloud?

No. On n8n Cloud, the Python option in the Code node doesn't allow importing any library, standard or third-party. The native Python runner with pip access requires building your own Docker image, which makes it a self-hosted feature by design.

What happens if a package is installed but missing from the allowlist?

The import fails at runtime, even though the package is physically present in the runner's environment. N8N_RUNNERS_EXTERNAL_ALLOW works as a strict allowlist: installing a package with uv pip isn't enough, you also have to add it explicitly to that variable for the Task Runner to accept importing it.

Should every Python script be migrated to the native runner?

No. For plain parsing or transformations with no external dependency, Python (Beta) on Pyodide stays simpler: nothing to build, and it works the same on Cloud and self-hosted. The native runner earns its keep when a workflow genuinely needs a third-party library such as pandas, numpy, or an internal in-house library.

RAG Assistant Pack

€119