nanopython¶
Python where CPython doesn't fit. A browser tab. A small Linux daemon. A native scripting target on macOS or Linux. Anywhere a multi-megabyte CPython install or a 30 MB Pyodide download is too much, and yet you still want real Python (floats, dicts, classes, comprehensions, dataclasses, the everyday stdlib), nanopython is a small runtime that fits.
Why nanopython exists¶
There are three good ways to run Python today. Each has a place it doesn't belong.
- CPython is where Python is real. It's also multi-megabyte at rest, hundreds of milliseconds cold, and comes with a stdlib that assumes a full operating system.
- Pyodide brings CPython to the browser at roughly 30 MB of wasm plus a stdlib download. Excellent for scientific-computing kernels; heavy for a page that just wants a Python snippet.
- MicroPython proved a small Python is possible. Its target is 256 KB flash on a microcontroller, and its distribution ecosystem, its stdlib coverage, and its wasm story all reflect that focus.
Between those, there's a gap: the surfaces where you want real Python, but where "multi-megabyte" is too much and "microcontroller" is the wrong shape. A browser tab. A stdlib-only Linux daemon. A native binary you want to ship at under a megabyte. nanopython is aimed at that gap.
What you get¶
Three concrete outcomes today (all measured, all reproducible):
- In a browser tab. ~270 KB of wasm after
wasm-opt -Oz, loads in well under a second on a typical connection. Python code touches the DOM directly throughimport js(ADR 006):js.document.body.textContent = "hi"works from Python. - As a small Linux daemon. hop3-rootd is a 6 KLOC stdlib-only privileged Linux daemon (systemd-managed, Unix-socket RPC, real cgroup / mount / firewall orchestration). Running on nanopython it uses ~3.3 MB RSS vs ~17.4 MB on CPython 3.14: a 5.3× reduction. Full case study in TR-002.
- As a native scripting target. ~550 KB static binary on arm64/x86_64 macOS or Linux. Ships the POSIX subset a Python daemon reaches for:
os,socket,select,signal,subprocess,pwd,grp, pluspathlib,datetime,dataclasses,logging,unittest.mock,pytest_lite.
Who this is for¶
- Web developers who want Python running in a browser tab without a 30 MB toolkit and a WASI shim they didn't choose.
- Systems developers with a stdlib-only Linux daemon or a small scripting target, who care about RAM and startup time.
- Anyone curious about a real-language runtime built as an incremental C→Zig strangler under a byte-exact oracle. The methodology is documented as a self-contained paper in TR-001.
What's here now¶
| Native | Wasm | |
|---|---|---|
| Byte-exact against vendor MicroPython (nano config) | 541/541 | 490/541 (52 documented walls) |
| Extended-semantics corpus (full config) | 545/552 (98.7%) | n/a |
| Integration smoke (both arms) | 77/77 | 77/77 |
| Cold-start RSS on a real 6 KLOC Linux daemon | ~3.3 MB vs CPython's ~17.4 MB | n/a |
| Shipping artifact size | ~550 KB ReleaseSmall | ~270 KB post-wasm-opt -Oz |
v0.7.1 is the current release; v0.8 is in flight, headline is the full-unix profile that made the hop3-rootd result possible.
Where to go next¶
- Try it out. Getting Started walks from an empty page to
hello worldrunning in wasmtime and in the browser. - Decide whether to use it. vs MicroPython has the compatibility surface; Compatibility matrix has per-program status.
- Read the design. Architecture covers the runtime's shape; the Strangler Journey tells the story of the port; TR-001 is the methodology paper.
- Read the decisions. The ADR series records every architectural call.
How it works (in a paragraph)¶
nanopython started as a strangler port of MicroPython to Zig, verified byte-for-byte against MicroPython's own test corpus at every commit. Zig's error union (PyError!T) replaced MicroPython's setjmp/longjmp-based exception machinery, which is what made wasm viable (wasm lacks native setjmp). Per-feature build flags decompose the runtime into orthogonal lanes, so each build is exactly the surface a given target needs. The single explicit compatibility contract today is the .mpy v6 bytecode format: zigpy-compile's output runs on the upstream MicroPython VM, and vice-versa. Beyond that, nanopython has been diverging as its own use cases pulled it in useful directions; see vs MicroPython for the current divergences and Architecture for the runtime's shape.