Build a self-hosted Pyodide distribution with additional PyPI packages, ready to upload to S3 (or any static file host).
- Downloads the Pyodide release tarball for each version found in
requirements/ - Downloads extra PyPI packages (pure-Python wheels) from
requirements/{version}.txt - Registers the extra wheels in
pyodide-lock.jsonso Pyodide can find them - Outputs everything to
dist/v{version}/full/— ready to sync to S3
The resulting S3 structure supports URLs like:
https://pyodide.company.com/v0.27.5/full/pyodide.js
Create requirements/{version}.txt (e.g. requirements/0.27.5.txt) for each Pyodide version you want to build, and list the packages you want:
xlwings # required
python-dotenv # required
black # requiredUnless you need a specific version of the package, adding packages without pinning the version is ok as they will be pinned in pyodide-lock.json. Only pure-Python wheels py3-none-any) are supported. Platform-specific or C-extension packages must be built for Emscripten/WASM separately.
Install uv if you haven't yet:
- Windows:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" - macOS / Linux:
curl -LsSf https://astral.sh/uv/install.sh | sh
Then run the build script:
uv run build.pyThe Pyodide tarball is cached in the current directory to avoid re-downloading on subsequent runs.
Install the aws CLI.
aws s3 sync ./dist/ s3://my-pyodide-bucket/Pair with a CloudFront distribution pointing at the bucket.
-
Set CORS headers: Bucket → Permissions → CORS configuration, e.g.,:
[ { "AllowedOrigins": ["*"], "AllowedMethods": ["GET", "HEAD"], "AllowedHeaders": ["*"] } ] -
Set
Cache-Control: immutableheaders on the objects for optimal performance. -
For regulated use cases where the Python environment must be frozen at a point in time consider enabling S3 Object Lock (WORM mode) on the bucket for write-once guarantees.