You’re organizing a Python workshop or teaching a class that uses Jupyter notebooks. The first question that comes up is almost always the same: how do I get everyone running notebooks without spending an hour on installation?
The traditional answer has been JupyterHub — a server that hosts Jupyter for all your participants. But there’s a simpler option that works for many scenarios: JupyterLite, which runs Python entirely in the browser with zero server infrastructure.
An important caveat: Software Carpentry workshops have an explicit goal that students leave with a functioning local Python installation they can continue using after the workshop. In that case, JupyterLite is not a replacement — the local install is the point. This guide is targeted at the many other workshops and classes that instead want to focus on teaching a specific package or subject and do not care much about the local environment of the students. For those, JupyterLite eliminates the installation hurdle entirely and lets you focus on the content.
JupyterHub: Powerful but Demanding
JupyterHub is the gold standard for multi-user notebook hosting. It gives every participant their own isolated Jupyter server, with full access to the host’s Python environment, filesystem, and computing resources.
When you need JupyterHub:
- Your workshop requires GPU access or heavy computation
- Participants need to work with large datasets that don’t fit in browser memory
- You need persistent storage across sessions
- You’re running custom kernels (R, Julia, etc.) beyond Python
- Your code requires network access to external APIs or databases during execution
- You need to run code that depends on native system libraries not available in WebAssembly
The trade-off? JupyterHub requires a server (cloud VM, Kubernetes cluster, or HPC system), ongoing maintenance, and someone to manage it. If you’re deploying on cloud infrastructure, I’ve written about deploying JupyterHub on OpenStack Magnum with OpenTofu — it works well, but it’s not trivial.
JupyterLite: Zero Server, Zero Installation
JupyterLite takes a completely different approach: it runs a full Python environment compiled to WebAssembly directly in the browser. No server, no installation, no setup time — participants just open a URL and start coding.
JupyterLite is ideal when:
- You want zero setup time — participants open a link and start coding immediately
- You’re teaching introductory Python with standard scientific packages
- Your workshop is short (a few hours) and doesn’t need persistent storage
- You don’t have infrastructure budget or time to set up a server
- You want participants to continue practicing at home without installing anything
- You need offline capability — once loaded, notebooks work without internet
Scientific Python in the Browser
A common concern is whether the browser-based Python environment can handle real scientific computing. Thanks to Pyodide (the Python-in-WebAssembly runtime that powers JupyterLite), many of the most important scientific Python packages work out of the box — including packages with C extensions that have been compiled to WebAssembly:
| Package | What It Does | C Extensions? |
|---|---|---|
| NumPy | Array computing, linear algebra | Yes |
| SciPy | Scientific algorithms, optimization, statistics | Yes |
| Matplotlib | Plotting and visualization | Yes |
| Pandas | Data manipulation and analysis | Yes (via NumPy) |
| scikit-learn | Machine learning | Yes |
These five packages cover the vast majority of introductory scientific Python curricula. In fact, the entire Software Carpentry Python Novice curriculum — both the Inflammation and Gapminder tutorials — runs perfectly in JupyterLite because it only needs NumPy, Matplotlib, and Pandas.
Other notable packages available in Pyodide include scikit-image, statsmodels, sympy, and astropy. You can check the full list of available packages in the Pyodide documentation.
What Doesn’t Work (Yet)
JupyterLite has some limitations you should be aware of:
- Network access from Python: The browser security model restricts raw socket access, so packages like
astroquerythat make direct HTTPS connections won’t work - HDF5 support:
h5pyandpytablesare not currently available in Pyodide - Very large datasets: Browser memory is limited (typically 2-4 GB per tab)
- GPU computing: No CUDA or GPU access from WebAssembly
- Persistent filesystem: Data saved in the notebook disappears when you close the tab (though you can download notebooks)
- Custom kernels: Only Python (via Pyodide) and JavaScript kernels are available
A Real Example: Software Carpentry Tutorials on JupyterLite
To demonstrate that JupyterLite works for real teaching material, I’ve deployed the Software Carpentry Python tutorials as a live JupyterLite site:
https://zonca.github.io/jupyterlite-carpentry/lab/
This site includes two complete tutorials converted from the original Carpentries markdown episodes into interactive notebooks:
- Python Novice: Inflammation — Introduction to Python using inflammation data analysis (NumPy, Matplotlib)
- Python Novice: Gapminder — Introduction to Python using Gapminder GDP data (Pandas, Matplotlib)
The source code for this deployment is at https://github.com/zonca/jupyterlite-carpentry — it uses GitHub Pages with a GitHub Actions workflow that builds the JupyterLite site automatically on every push to main.
How the Deployment Works
The entire deployment is surprisingly simple:
- Notebooks and data live in a
content/directory jupyter lite build --contents contentcompiles them into a static JupyterLite site- The built
_output/directory is deployed to GitHub Pages via Actions - Participants access the site at
https://<username>.github.io/<repo>/lab/
That’s it. No Kubernetes, no Helm charts, no SSL certificates, no user authentication. The entire site is just static files served by GitHub.
GitHub Actions Configuration
The deployment is automated with a simple two-job workflow:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install -r requirements.txt
- run: make build
- uses: actions/upload-pages-artifact@v3
with:
path: _output
deploy:
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
steps:
- uses: actions/deploy-pages@v4The build job installs the JupyterLite dependencies, runs jupyter lite build, and uploads the generated static site as an artifact. The deploy job takes that artifact and publishes it to GitHub Pages — but only on pushes to main, not on pull requests. The permissions block grants the workflow access to the GitHub Pages API. You also need to enable GitHub Pages in your repository settings and set the Source to “GitHub Actions” (not “Deploy from a branch”).
Decision Guide: JupyterHub or JupyterLite?
| Feature | JupyterLite | JupyterHub |
|---|---|---|
| Setup effort | Minutes (push to GitHub) | Hours to days |
| Server cost | Free (GitHub Pages) | Cloud VM costs |
| Installation | None for participants | None for participants |
| Python packages | Pyodide subset | Full conda/pip |
| Data size | Small (< 100 MB) | Unlimited |
| Computation | Browser-only | Full server resources |
| Persistence | Download only | Persistent home directory |
| Network access | Limited | Full |
| Offline | Works after loading | Requires connection |
| Maintenance | None | Ongoing |
My recommendation: Start with JupyterLite for introductory workshops and short courses. If your curriculum fits within the Pyodide package ecosystem (and most introductory Python does), you’ll save enormous amounts of setup time and infrastructure cost. Graduate to JupyterHub only when you need capabilities that the browser can’t provide.
Getting Started
To create your own JupyterLite deployment with custom notebooks:
pip install jupyterlite-pyodide-kernel jupyterlite
jupyter lite build --contents /path/to/your/notebooks
jupyter lite serveOr fork zonca/jupyterlite-carpentry and replace the notebooks with your own — the GitHub Actions workflow will build and deploy automatically.