Personal Learnings← Simon Willison  Library

Simon Willison · Tech & AI

Publishing WASM wheels to PyPI for use with Pyodide

TIER 4   2026-06-13

<p>The <a href="https://blog.pyodide.org/posts/314-release/">Pyodide 314.0 release announcement</a> (via <a href="https://news.ycombinator.com/item?id=48462759">Hacker News</a>) includes news I've been looking forward to for a long time:</p>

<blockquote>

<p>You can now publish Python packages built for Pyodide (or any Python runtime compatible with <a href="https://pyodide.org/en/stable/development/abi.html">the PyEmscripten platform defined in PEP 783</a>) directly to PyPI and install them at runtime.</p>

<p>Previously, the Pyodide maintainers had to maintain, build, and host over 300 packages ourselves. This created a significant burden on our maintainers and became a major bottleneck for the community, as every new package required manual review.</p>

<p>Moving forward, package maintainers can simply build and publish Pyodide wheels to PyPI, just as they do for native wheels on Linux, macOS, or Windows.</p>

</blockquote>

<p>Here's the <a href="https://github.com/pypi/warehouse/pull/19804">PR to PyPI itself supporting this</a>, which landed on April 21st.</p>

<p>I adore <a href="https://pyodide.org">Pyodide</a>, and have been frustrated in the past by this limitation. It's possible to compile C or Rust extensions to WASM in a wheel file, but before now there was no easy way to distribute them.</p>

<p>Thanks to the efforts of a whole lot of people, that's now been fixed!</p>

<h4 id="trying-it-out-with-luau-wasm">Trying it out with luau-wasm</h4>

<p>I decided to celebrate by finding something I could package. I have quite a few experimental Pyodide projects lying around, but the best fit for this looked to be my <a href="https://github.com/simonw/research/tree/main/pluau-wasm-pyodide#readme">Luau WebAssembly research spike</a> from 9th March.</p>

<p><a href="https://luau.org">Luau</a> is a "small, fast, and embeddable programming language based on Lua with a gradual type system", <a href="https://luau.org/news/2022-11-04-luau-origins-and-evolution/">developed by Roblox</a> and released under an MIT license.</p>

<p>It's written in C++. I already knew it was possible to compile it to WebAssembly and get it running inside of Pyodide, so I <a href="https://gist.github.com/simonw/1761eab6ba11d4053f56f955a28ad76b">set Codex + GPT-5.5 xhigh</a> the task of packaging my experiment up and publishing it to PyPI using GitHub Actions.</p>

<p>It took some iteration, but here's the result: <a href="https://pypi.org/project/luau-wasm/">luau-wasm</a> is a brand new PyPI package which publishes a 276KB <code>luau_wasm-0.1a0-cp314-cp314-pyemscripten_2026_0_wasm32.whl</code> file which can be used in Pyodide like this:</p>

<pre><span class="pl-k">import</span> <span class="pl-s1">micropip</span>

<span class="pl-k">await</span> <span class="pl-s1">micropip</span>.<span class="pl-c1">install</span>(<span class="pl-s">"luau-wasm"</span>)

<span class="pl-k">import</span> <span class="pl-s1">luau_wasm</span>

<span class="pl-en">print</span>(<span class="pl-s1">luau_wasm</span>.<span class="pl-c1">execute</span>(<span class="pl-s">r'''</span>

<span class="pl-s">local animals = {"fox", "owl", "frog", "rabbit"}</span>

<span class="pl-s">table.sort(animals, function(a, b) return #a &lt; #b end)</span>

<span class="pl-s">for i, name in animals do print(i .. ". " .. name .. " (" .. #name .. ")") end</span>

<span class="pl-s">'''</span>))</pre>

<p>You can run that code <a href="https://pyodide.org/en/stable/console.html">in the Pyodide REPL demo</a> to see it in action.</p>

<p>The <a href="https://github.com/simonw/luau-wasm">GitHub repo for luau-wasm</a> includes all of the build and deploy scripts (using the latest <a href="https://github.com/pypa/cibuildwheel">cibuildwheel</a>) and also deploys an HTML demo page which loads Pyodide, installs <code>luau-wasm</code> and provides an interface for trying it out: <a href="https://simonw.github.io/luau-wasm/">https://simonw.github.io/luau-wasm/</a></p>

<p><img src="https://static.simonwillison.net/static/2026/luau-wasm.jpg" alt="Screenshot of a web app titled &quot;Luau WASM&quot; with subtitle &quot;Run Luau in the browser through Pyodide after installing the luau-wasm WebAssembly wheel from PyPI.&quot; A green &quot;Ready&quot; status badge is at top right. Below are example buttons: &quot;Hello World&quot;, &quot;Variables&quot;, &quot;Tables&quot;, &quot;Fibonacci&quot;, &quot;Runtime Error&quot;. A &quot;LUAU SOURCE&quot; code editor contains: local function fib(n: number): number / if n &lt; 2 then return n end / return fib(n - 1) + fib(n - 2) / end / local out = {} / for i = 0, 12 do / table.insert(out, tostring(fib(i))) / end / print(table.concat(out, &quot;, &quot;)). On the right is an &quot;OUTPUT&quot; panel with a &quot;Copy&quot; button showing dark terminal output: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144. At the bottom left are a blue &quot;Run&quot; button, a &quot;Clear&quot; button, and the text &quot;6.0 ms&quot;." style="max-width: 100%;" /></p>

<h4 id="how-many-packages-are-using-this-so-far-">How many packages are using this so far?</h4>

<p>I was curious to see how many packages are currently publishing wheels for this platform.</p>

<p>After some <a href="https://chatgpt.com/share/6a2dee92-b110-83e8-9f53-ba9259b751ed">tinkering with ChatGPT</a> I got to <a href="https://gist.github.com/simonw/4a34a49fca63bc09c50bc31e17b3d33b?permalink_comment_id=6198602#gistcomment-6198602">this BigQuery SQL</a> which I ran against PyPI's <a href="https://packaging.python.org/en/latest/guides/analyzing-pypi-package-downloads/#public-dataset">public dataset on BigQuery</a>. Here's the <a href="https://gist.github.com/simonw/4a34a49fca63bc09c50bc31e17b3d33b">raw JSON</a> of query results and here's a SQLite SQL query <a href="https://lite.datasette.io/?json=https://gist.github.com/simonw/4a34a49fca63bc09c50bc31e17b3d33b#/data?sql=select%0A++name%2C%0A++platform_tag%2C%0A++matching_file_count%2C%0A++max%28latest_upload%29+as+latest_upload%2C%0A++example_files%0Afrom+%28%0A++--+your+existing+query+here%2C+without+order+by%0A++select%0A++++name%2C%0A++++platform_tag%2C%0A++++matching_file_count%2C%0A++++latest_upload%2C%0A++++example_files%0A++from+raw%0A%29%0Agroup+by+name%0Aorder+by+latest_upload+desc%3B">in Datasette Lite</a> which dedupes packages by most recent upload date.</p>

<p>If the query is right, there are currently 28 PyPI packages publishing with the new <code>pyemscripten_202*_wasm32</code> tags:</p>

<p><a href="https://pypi.org/project/luau-wasm/">luau-wasm</a>, <a href="https://pypi.org/project/uuid7-rs/">uuid7-rs</a>, <a href="https://pypi.org/project/cmm-16bit/">cmm-16bit</a>, <a href="https://pypi.org/project/pyOpenTTDAdmin/">pyOpenTTDAdmin</a>, <a href="https://pypi.org/project/imgui-bundle/">imgui-bundle</a>, <a href="https://pypi.org/project/numbertoolkit/">numbertoolkit</a>, <a href="https://pypi.org/project/bashkit/">bashkit</a>, <a href="https://pypi.org/project/geoarrow-rust-core/">geoarrow-rust-core</a>, <a href="https://pypi.org/project/arro3-io/">arro3-io</a>, <a href="https://pypi.org/project/arro3-core/">arro3-core</a>, <a href="https://pypi.org/project/arro3-compute/">arro3-compute</a>, <a href="https://pypi.org/project/onnx/">onnx</a>, <a href="https://pypi.org/project/powerfit-em/">powerfit-em</a>, <a href="https://pypi.org/project/tcod/">tcod</a>, <a href="https://pypi.org/project/chonkie-core/">chonkie-core</a>, <a href="https://pypi.org/project/tokie/">tokie</a>, <a href="https://pypi.org/project/robotraconteur/">robotraconteur</a>, <a href="https://pypi.org/project/pydantic_core/">pydantic_core</a>, <a href="https://pypi.org/project/yaml-rs/">yaml-rs</a>, <a href="https://pypi.org/project/cadquery-ocp-novtk-OCP.wasm/">cadquery-ocp-novtk-OCP.wasm</a>, <a href="https://pypi.org/project/uuid_utils/">uuid_utils</a>, <a href="https://pypi.org/project/base64_utils/">base64_utils</a>, <a href="https://pypi.org/project/pycdfpp/">pycdfpp</a>, <a href="https://pypi.org/project/lib3mf-OCP.wasm/">lib3mf-OCP.wasm</a>, <a href="https://pypi.org/project/typst/">typst</a>, <a href="https://pypi.org/project/toml-rs/">toml-rs</a>, <a href="https://pypi.org/project/onnx-weekly/">onnx-weekly</a>, <a href="https://pypi.org/project/dummy-pyodide-ext-test/">dummy-pyodide-ext-test</a></p>

<p>Here's hoping we see a whole lot more of those showing up over the coming months and years.</p>