PyScript client-side dependencies with py-config and micropip
Declare Python dependencies in a <py-config> block so PyScript loads them via Pyodide and micropip before any <py-script> runs. This enables browser-only demos with pure-Python packages while trading load size and memory for serverless execution.
09 Oct 2026, 06:59 UTC

Use py-config to declare packages and let PyScript load them before your code runs
If you need pure-Python libraries in the browser without a server, declare them in a <py-config> block. PyScript parses that config, boots Pyodide in a web worker, runs micropip installs for the listed packages, then executes <py-script> blocks in order. That means imports inside your scripts can assume the packages are present, provided the wheels exist for Pyodide.
How the load sequence works
Pyodide is the WebAssembly build of CPython used by PyScript. Micropip is the lightweight package installer bundled with Pyodide. At page start PyScript reads the config, downloads the Pyodide runtime, then installs each package listed under packages. Only after installs finish does script execution begin.
This is declarative rather than imperative. You do not call pip from Python code. The config is evaluated once per page load and is not re-run on reload.
Worked configuration for a browser-only numpy demo
Create an HTML file and open it in a modern browser. No build step or server is required for a static file.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>PyScript packages</title>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<body>
<div id="out"></div>
<py-config>
packages = ["numpy"]
</py-config>
<py-script output="out">
import sys
import numpy as np
arr = np.arange(5)
print("modules:", "numpy" in sys.modules)
print("arr:", arr.tolist())
</py-script>
</html>
Placeholders to adapt: replace numpy with other pure-Python or Pyodide-compatible packages, and change the output element id as needed. The script block runs only after the config packages are installed.
Practical verification without claiming a specific run result:
- Open DevTools console and look for Pyodide load and micropip messages that indicate the runtime is initializing.
- After the page settles, inspect
sys.modulesin a subsequent<py-script>block to confirm the requested package name is present. - Use the Network panel to measure total payload for the Pyodide core plus each wheel. Compare the size and time to your interactivity budget.
Limits and engineering trade-offs
Package availability is limited to Pyodide compatible wheels. Pure Python packages load reliably. Packages with compiled C extensions require a Pyodide build and may be missing or larger than server equivalents.
Large packages increase initial download and memory use. Pandas and scikit-learn can push browser memory limits and delay first paint. Micropip installs happen at startup and block script execution until complete, which can make the UI feel frozen if no loading indicator is shown.
Browser memory and network constraints can cause out-of-memory situations or long load times on slow connections. There is no native threading in the WebAssembly runtime, so CPU-bound work blocks the worker.
Use PyScript for small interactive demos, client-side validation, teaching notebooks, and offline serverless execution where the value of no backend outweighs load cost. Avoid it for heavy data processing or large ML models where download cost, memory limits, and lack of native threading dominate.
Common mistakes
Assuming imports are synchronous and available immediately. The config guarantees availability for scripts that run after the load phase, but dynamic imports added later still depend on the install having finished.
Using pip syntax instead of micropip. Do not call pip install inside <py-script>. Declare packages in <py-config> or use micropip API if you need runtime installs, accepting the async cost.
Expecting persistent virtual filesystem state across page reloads. The Pyodide filesystem lives in memory for the page session only. Reloading the page discards it.
Config syntax changed across PyScript major releases. Version-specific defaults for package loading and script execution order may differ, so pin the loader URL you test against and verify behavior in your target browser.
When you need rollback, there is no state change to revert for a read-only demo. If you wrote files to the virtual filesystem, they are lost on reload. For persistent data, export results to the DOM or download them rather than relying on in-memory files.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.