• Latest stable version: Pyodide 314.0.x (based on Python 3.14)
  • License: MPL-2.0
  • Official site: https://pyodide.org

1. What Is Pyodide?

Pyodide is a Python distribution for the browser and Node.jsthat compiles the entire CPython interpreter usingWebAssemblyandEmscripten. It lets you run Python code directly in a browser with no server involved, and it originated as a 2018 internal Mozilla project (iodide) before evolving into an independent community project after 2019.

Verification Notes (as of July 2026)

Item Original Claim Verification Result
Origin Started at Mozilla in 2018 Accurate
Version scheme Not mentioned Changed. Since June 2026, versioning shifted to track Python versions directly (0.29.x → 314.x, aligned with Python 3.14). Major releases now sync with upstream Python once a year
Performance 3–5x slower than native Mostly accurate. 3–5x for pure Python code; WASM-compiled C code runs at roughly 2–2.5x slower
Memory limit ~2GB Outdated. Currently usable up to the wasm32 address space limit of 4GB. Bugs related to addressing beyond 2GB have also recently been fixed
C extension packages Unusable unless ported Needs softening. Adoption of PEP 783 enables official pyemscripten-tagged binary wheel distribution on PyPI. 250+ C/C++/Rust extensions — NumPy, SciPy, cryptography, and more — are already ported
stdlib bundling Not mentioned Starting with 314.0, sqlite3 and lzma are included in the default bundle (unvendoring has been discontinued)

2. Key Features

Feature Description
In-browser Python execution Runs CPython 3.14 in a web browser with no server
JavaScript-Python FFI Automatic bidirectional object conversion, error propagation, mutual async/await support
Bundled scientific stack NumPy, pandas, SciPy, Matplotlib, scikit-learn, and more, prebuilt
micropip Installs pure-Python wheels and pyemscripten wheels from PyPI
Web API access Full access to browser APIs — DOM, fetch, Canvas, and more
Node.js support Runs in server-side/CLI environments via the pyodide npm package
PEP 783 standardization Secures an official PyPI distribution path for Emscripten wheels (2026)

3. Additional Capabilities (Not Covered in the Original)

3.1 JavaScript ↔ Python FFI Details

  • Proxy-based interoperability: PyProxy (references a Python object from JS), JsProxy (references a JS object from Python)
  • Automatic type conversion: JS Array ↔ Python list, JS Map ↔ Python dict, TypedArray ↔ memoryview
  • BigInt round-tripping: starting in 314.0, pyodide.ffi.JsBigInt supports round-trip conversion of integers exceeding 2^53 with JS bigint
  • Mutual exception propagation: an exception thrown in one language can be caught in the other

3.2 Running in a Web Worker

To avoid blocking the main thread, running Pyodide inside a Web Worker has become the de facto standard pattern. Heavy computation (pandas processing, model inference) is isolated in the worker, exchanging only results via postMessage.

3.3 Virtual Filesystem (Emscripten FS)

  • Memory-based MEMFS is the default; IndexedDB-based IDBFS enables persistence across browser sessions
  • The pyodide.FS API lets you directly control file reads/writes from the JS side

3.4 Dual Package Loading

Method Purpose
pyodide.loadPackage() Loads packages prebuilt for the Pyodide CDN (e.g., NumPy)
micropip.install() Installs pure-Python wheels and pyemscripten wheels from PyPI
loadPackagesFromImports() Analyzes import statements in code and automatically loads required packages

3.5 Developer Tooling Ecosystem

Tool Function
pyodide-build Cross-builds C/Rust extension packages into pyemscripten wheels
pytest-pyodide Automates testing against Pyodide across Chrome/Firefox/Node runtimes
pyodide-pack Minimizes distribution bundles (removes unused modules)
auditwheel-emscripten Validation tool for Emscripten wheels
Pyodide CLI Creates a venv-like environment and runs a REPL via the pyodide command in the terminal

3.6 SharedArrayBuffer and Synchronous I/O

With COOP/COEP headers configured, synchronous communication between the worker and main thread becomes possible via SharedArrayBuffer, which can be used to emulate synchronous standard input such as input().


4. Advantages

  1. Lower server costs and simpler infrastructure — Python computation runs on the client, so the server only handles essentials like auth and database access. Compute cost doesn't scale proportionally with user count.
  2. No installation, runs immediately — Runs Python with just a browser. Can operate offline after the first load.
  3. Full integration with JavaScript — Bidirectional automatic conversion, exception propagation, async/await support.
  4. Rich scientific computing ecosystem — Use essential data science libraries with no extra setup.
  5. Ideal for education and interactive content — Build serverless notebook environments with tools like JupyterLite. Student code is sandboxed in the browser, eliminating server-side security risk.
  6. (New) Packaging standardization — With PEP 783 adopted, package authors can publish Emscripten wheels directly to PyPI. Wheel compatibility across Pyodide releases within the same Python version is guaranteed.

5. Disadvantages

  1. Performance overhead — Pure Python code runs about 3–5x slower than native; WASM-compiled C code about 2–2.5x slower. The root cause is interpreter execution with no JIT.
  2. Memory constraints — Capped at roughly 4GB due to the wasm32 address space limit. The initial load alone consumes hundreds of MB, which becomes a burden with multiple tabs on low-spec devices. (The old 2GB hard limit has been resolved)
  3. Initial load size — The core runtime alone is several MB; loading NumPy/pandas and similar requires tens of MB more. A caching strategy (Service Worker, CDN) is effectively mandatory.
  4. Package coverage limits — Significantly improved by PEP 783, but OS-dependent features (multiprocessing, low-level sockets, synchronous sleep, etc.) remain limited. This is not a fully equivalent implementation of CPython.
  5. Network request restrictions — Subject to browser CORS policy. Requires using pyodide.http.pyfetch instead of requests, or working around it with a proxy.
  6. Browser requirements — Requires a modern browser with WebAssembly support. Features relying on SharedArrayBuffer additionally require COOP/COEP headers to be configured.

6. Getting Started

6.1 Browser: Start With One CDN Line

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/pyodide/v314.0.2/full/pyodide.js"></script>
</head>
<body>
  <script type="module">
    const pyodide = await loadPyodide();
    // Basic execution
    console.log(pyodide.runPython("1 + 2"));  // 3

    // Multi-line Python code
    pyodide.runPython(`
      import sys
      print(f"Python {sys.version} in the browser")
    `);
  </script>
</body>
</html>

Always pin the version string (v314.0.2) at deployment time. Never use a non-versioned URL like dev in production.

6.2 Loading a Prebuilt Package (NumPy Example)

await pyodide.loadPackage("numpy");
pyodide.runPython(`
  import numpy as np
  a = np.random.rand(1000, 1000)
  print(a.mean())
`);

6.3 Installing PyPI Packages With micropip

await pyodide.loadPackage("micropip");
const micropip = pyodide.pyimport("micropip");
await micropip.install("cowsay");   // pure Python wheel
pyodide.runPython(`
  import cowsay
  cowsay.cow("Hello from PyPI")
`);

6.4 Exchanging Data Between JavaScript and Python

// JS → Python
pyodide.globals.set("js_data", [10, 20, 30]);
const result = pyodide.runPython(`
  data = js_data.to_py()      # JsProxy → Python list
  sum(data)
`);
console.log(result);  // 60

// Python → JS
const pyDict = pyodide.runPython(`{"en": "London", "jp": "Tokyo"}`);
console.log(pyDict.toJs());   // Map(2) { "en" → "London", ... }
pyDict.destroy();             // Free PyProxy memory (prevents leaks)

6.5 Async Execution and Network Requests

await pyodide.loadPackage("micropip");
const out = await pyodide.runPythonAsync(`
  from pyodide.http import pyfetch
  resp = await pyfetch("https://api.github.com/repos/pyodide/pyodide")
  data = await resp.json()
  data["stargazers_count"]
`);

6.6 Web Worker Pattern (Recommended Production Structure)

// worker.js
importScripts("https://cdn.jsdelivr.net/pyodide/v314.0.2/full/pyodide.js");

let pyodideReady = loadPyodide();

self.onmessage = async (e) => {
  const pyodide = await pyodideReady;
  await pyodide.loadPackagesFromImports(e.data.code);
  const result = await pyodide.runPythonAsync(e.data.code);
  self.postMessage({ result });
};
// main.js
const worker = new Worker("worker.js");
worker.postMessage({ code: "import numpy as np; float(np.pi)" });
worker.onmessage = (e) => console.log(e.data.result);

6.7 Using Pyodide in Node.js

npm install pyodide
import { loadPyodide } from "pyodide";

const pyodide = await loadPyodide();
console.log(pyodide.runPython("2 ** 10"));  // 1024

6.8 Building Your Own Package (C/Rust Extensions)

pip install pyodide-build
pyodide build            # generates a pyemscripten wheel from the project root

The resulting wheel can be uploaded directly to PyPI under the PEP 783 standard and installed via micropip.


7. Comparison With Competing Products

Approaches to running Python in the browser fall broadly into three families: (A) porting CPython itself to WASM, (B) reimplementing a Python interpreter in JavaScript, (C) transpiling Python code into JavaScript.

Product Approach Strengths Weaknesses Primary Use
Pyodide (A) CPython → WASM Full CPython compatibility, scientific stack, PEP 783 standardization Initial load size, interpreter speed Data science, general purpose
PyScript Framework on top of Pyodide/MicroPython Embed Python with just an HTML tag, lowest barrier to entry Not its own runtime (depends on Pyodide underneath), abstraction overhead Education, prototyping, widgets
MicroPython (WASM) Lightweight Python reimplementation → WASM Load size in the hundreds of KB, best startup speed Significantly reduced stdlib/CPython compatibility, no C extension ecosystem Lightweight scripting, embedded widgets
Brython (B) Interpreter reimplemented in JS Light to load, natural DOM manipulation via text/python script tags, CPython-level speed for simple operations No C extensions like NumPy, large performance variance on complex operations DOM-centric web scripting
Skulpt (B) Interpreter reimplemented in JS Fully client-side execution, validated on education platforms (Anvil, etc.) Tens of times slower than CPython, limited Python feature coverage Beginner education, tutorials
Transcrypt (C) Python → JS transpiler Output is pure JS, so it loads/runs fast, can directly use JS libraries Not a runtime interpreter (limits dynamic features), requires a build step Writing frontend apps with Python syntax
CPython WASI build (A) CPython → WASI Officially supported by upstream CPython (tier 2), well-suited to serverless/edge runtimes Browser integration (FFI, DOM) less mature than Pyodide Edge computing, sandboxed execution

Derivative Ecosystem (Products Built on Pyodide, Not Competitors)

Product Description
JupyterLite Serverless, in-browser Jupyter notebook. Uses Pyodide as the kernel
stlite Runs Streamlit apps serverlessly in the browser
marimo (WASM mode) Browser-executable version of the reactive Python notebook
Cloudflare Workers Python Uses Pyodide to power Python support in the edge runtime

Selection Guide

Requirement Recommendation
Need a scientific stack like NumPy/pandas Pyodide
Want to embed Python quickly with just HTML PyScript
Load size is the top priority (hundreds of KB) MicroPython (WASM) or Brython
Lightweight scripting centered on DOM manipulation Brython
Beginner programming education platform Skulpt or PyScript
Deploying build output as JS Transcrypt
Serverless/edge sandboxed execution CPython WASI or Pyodide (Node)

8. Use Case Summary

Good Fit Poor Fit
Educational interactive content Large-scale data processing (multiple GB or more)
Prototyping and demos Applications requiring real-time low latency
Scientific computation visualization, in-browser analysis tools Complex networking/socket operations
Serverless Python applications OS-dependent workloads such as multiprocessing
Client-side processing of sensitive data (data never leaves the browser) Cases requiring every PyPI package

9. Conclusion

Pyodide started as a project that opened up the possibility of "running Python on the web without a server," and with the 2026 adoption of PEP 783 and a release scheme now tied to Python versions, it has established itself as the de facto standard platform for browser-based Python. The structural limitations of performance (3–5x slower than native) and initial load size remain, so it's reasonable to apply it to education, visualization, client-side data processing, and serverless tools rather than compute-intensive workloads. The basic rule of thumb: choose MicroPython/Brython if lightweight footprint is the top priority, and choose Pyodide if you need the full CPython ecosystem.