Skip to main content
Python code inside ws.execute('python3 ...') can open(), os.listdir(), pathlib.Path() etc. against any registered Mirage mount. The shim routes those calls through Mirage’s mount layer (RAM, S3, Linear, GDocs, Slack, anything you’ve registered).

What works

The first read fetches via the resource and caches in MEMFS. Subsequent reads are sync.

What doesn’t work

How it works (one paragraph)

Pyodide’s in-memory FS (MEMFS) is the sync facade. At addMount, Mirage walks the prefix and copies files into MEMFS. Python reads hit MEMFS directly, fast, no network. On a miss (path not yet in MEMFS but the prefix is registered), the shim catches the error, calls back through the bridge via JSPI to fetch it, populates MEMFS, and retries. Writes are intercepted on close() and flushed back through Mirage’s write op.

Quick start (TypeScript)

See the full demo at examples/typescript/pyodide/vfs.ts.

Python packages (PIL, numpy, pandas, …)

Pyodide ships CPython, but third-party packages aren’t loaded until you import them. Mirage scans the code you run for import statements and auto-fetches matching packages on demand, so from PIL import Image, import numpy as np, import pandas as pd all just work the first time. Subsequent calls hit Pyodide’s package cache. If you need to opt out (e.g., to keep workspace startup lean):

Resource compatibility

Runtime requirements

The shim uses JSPI to bridge sync Python calls to async JS.
  • Chrome / Edge 137+ (May 2025): works out of the box
  • Firefox: behind javascript.options.wasm_js_promise_integration
  • Node 24+: pass --experimental-wasm-jspi (vitest config already does this)
  • Cloudflare Workers: Python Workers with JSPI runtime
Without JSPI, reads of preloaded files still work but writes throw RuntimeError: Cannot stack switch on close().
To run examples directly:

Errors you might see

See also