cheat sheet

jupyter

Package-level reference for the jupyter meta-package on PyPI — install variants, what it pulls in, version policy, and alternatives.

jupyter

What it is

jupyter is the historical meta-package on PyPI that pulls in the full Jupyter notebook stack: the IPython kernel, the classic Notebook web interface, nbconvert, qtconsole, and supporting libraries. It is maintained by Project Jupyter, a NumFOCUS-sponsored umbrella organization.

The Jupyter ecosystem has since split into many independently-versioned packages — jupyterlab, notebook, ipykernel, nbclient, nbconvert, jupyter-server — and most modern installs prefer jupyterlab directly. Reach for the jupyter meta-package only when you want the classic Notebook + qtconsole experience bundled together; reach for jupyterlab for the modern IDE-like interface, or just ipykernel if you only need the kernel for an external editor like VS Code.

Install

bash
pip install jupyterlab   # recommended modern install

Output: (none — exits 0 on success)

bash
pip install jupyter      # legacy meta-package (classic Notebook + qtconsole)

Output: (none — exits 0 on success)

bash
uv add jupyterlab

Output: resolved + added to pyproject.toml

bash
pipx install jupyterlab  # global, isolated install for ad-hoc use

Output: installs jupyter-lab on PATH in a dedicated venv

bash
conda install -c conda-forge jupyterlab

Output: preferred for ML/data-science envs where conda solves CUDA + Python + JupyterLab together.

Versioning & Python support

  • The jupyter meta-package itself is on a slow major-release cadence (currently 1.x); the components it depends on each have their own faster cycles.
  • jupyterlab is on the 4.x series as of late 2025, with monthly minor releases.
  • notebook was rewritten on top of jupyter-server for its 7.x line — the old 5.x/6.x "classic Notebook" is a separate code path.
  • Python 3.9+ supported across the active component matrix.
  • Loose semver, with notable historic ecosystem breaks (the nbformat v4 schema bump, the notebook 6 → 7 rewrite).

Package metadata

  • Maintainer: Project Jupyter (NumFOCUS fiscally sponsored)
  • Project home: github.com/jupyter/jupyter (meta-repo)
  • Docs: docs.jupyter.org · jupyterlab.readthedocs.io
  • PyPI: pypi.org/project/jupyter · pypi.org/project/jupyterlab
  • License: BSD-3-Clause
  • Governance: Project Jupyter steering council
  • First released: 2015 (Project Jupyter); IPython notebook dates to 2011
  • Downloads: tens of millions per month across the ecosystem — jupyterlab and notebook both in the PyPI top 100

Optional dependencies & extras

jupyter is itself a thin meta-package — its value is the dependency tree it pulls in. Key components:

  • ipykernel — the Python kernel; required by every notebook
  • notebook — the classic web interface (now in 7.x, built on jupyter-server)
  • jupyterlab — the modern web IDE
  • nbconvert — convert .ipynb to HTML, PDF, Markdown, slides
  • nbformat — the on-disk .ipynb schema
  • qtconsole — Qt-based REPL with rich output
  • jupyter-console — terminal REPL
  • jupyter-server — the HTTP server shared by notebook 7 and jupyterlab

Common companions (install separately):

  • ipywidgets — interactive widgets (sliders, dropdowns) inside cells
  • jupytext — pair .ipynb notebooks with .py / .md for clean git diffs
  • nbstripout — git filter that strips notebook outputs on commit
  • jupyterlab-git, jupyterlab-lsp, jupyterlab-vim — JupyterLab extensions
  • voila — turn a notebook into a standalone dashboard
  • papermill — parameterize and execute notebooks programmatically

Alternatives

PackageTrade-off
jupyterlabThe modern interface. Install this directly unless you specifically want the legacy meta-bundle.
notebookClassic single-document interface (7.x rebuild). Lighter than JupyterLab.
marimoReactive notebook with a dependency graph; cells re-run automatically. Reproducibility-first design.
nbtermNotebook UI inside a terminal — no browser.
vscode + Python extensionRun .ipynb files in VS Code directly via ipykernel. Skip Jupyter's web UI entirely.
colab / kaggleHosted Jupyter with free GPUs; no local install.

Common gotchas

  1. jupyter vs jupyterlab vs notebook. Installing the meta-package jupyter brings the classic Notebook stack but not JupyterLab. Most users want pip install jupyterlab. The jupyter command (jupyter notebook, jupyter lab, jupyter console) is what's shared.
  2. Kernel-spec leaks across venvs. ipykernel registers a kernel by name globally in ~/Library/Jupyter/kernels (macOS) or ~/.local/share/jupyter/kernels (Linux). If you create a new venv and pip install ipykernel, the kernel name python3 may still point at the old venv. Register explicitly: python -m ipykernel install --user --name myproject --display-name "Py 3.12 (myproject)".
  3. Browser launch fails on remote / headless hosts. jupyter lab tries to open a browser; on a headless server it just hangs. Pass --no-browser --ip=0.0.0.0 and copy the token URL from the terminal.
  4. Classic Notebook 6 vs 7 are different code paths. Extensions written for Notebook 6 do not work in Notebook 7. Both pin to incompatible nbclassic/jupyter-server ranges. If you must stay on 6, pin: pip install "notebook<7".
  5. pip install jupyter does not install JupyterLab extensions. Extensions are themselves PyPI packages (jupyterlab-git, jupyterlab-lsp); install them separately and restart jupyter lab to discover them.
  6. .ipynb files contain output + metadata that pollutes git diffs. Without nbstripout or jupytext, every cell re-run produces a noisy commit. Configure one of them per-repo.
  7. Output cells can contain MBs of base64 PNGs. Notebooks accidentally committed with large embedded images bloat the repo permanently. Add a pre-commit hook with nbstripout to strip on commit.

Real-world recipes

These are package-level recipes — install layout, kernel management, deployment. For magic commands, widgets, and notebook-internal API see the companion Python article.

Recipe 1 — one kernel per project virtualenv

The canonical multi-project layout: one venv per project, each registered as its own kernel.

bash
cd ~/projects/analytics
python -m venv .venv
source .venv/bin/activate
pip install ipykernel jupyterlab pandas matplotlib
python -m ipykernel install --user \
    --name analytics \
    --display-name "Py 3.12 — analytics"

Output: kernel registered at ~/.local/share/jupyter/kernels/analytics/kernel.json (Linux) or ~/Library/Jupyter/kernels/analytics/ (macOS). The kernel JSON points at the venv's python — so any JupyterLab instance can launch this kernel.

List kernels:

bash
jupyter kernelspec list

Output:

text
Available kernels:
  analytics    /home/alice/.local/share/jupyter/kernels/analytics
  python3      /home/alice/.local/share/jupyter/kernels/python3

Recipe 2 — execute a parametrised notebook from CI with papermill

bash
pip install papermill
papermill report.ipynb out.ipynb -p month "2026-05" -p region us-east

Output: out.ipynb is the notebook executed with month and region cell variables substituted. Combined with nbconvert, this is the canonical "scheduled report" pipeline.

bash
jupyter nbconvert out.ipynb --to html --output report-2026-05.html

Output: standalone HTML — drop into any static-file host.

Recipe 3 — pair .ipynb with .py for clean git diffs

bash
pip install jupytext
jupytext --set-formats ipynb,py:percent notebook.ipynb

Output: every save in JupyterLab writes both notebook.ipynb (full, for execution) and notebook.py (text, for diffing/reviewing). Commit the .py; gitignore the .ipynb if you don't need cached outputs.

Recipe 4 — strip outputs on commit with nbstripout

bash
pip install nbstripout
nbstripout --install        # configures git to filter notebooks on commit

Output: every git add of a .ipynb runs the filter and strips outputs, execution_count, and runtime metadata. The on-disk file is unchanged — only the staged copy is clean.

Recipe 5 — turn a notebook into a runtime artifact via nbconvert

bash
# Static HTML (the most useful default)
jupyter nbconvert analysis.ipynb --to html

# Self-contained slides for a talk
jupyter nbconvert talk.ipynb --to slides --post serve

# Convert to a runnable .py
jupyter nbconvert analysis.ipynb --to script

Output: analysis.html, a live RevealJS slide deck on http://localhost:8000, and analysis.py respectively.

Production deployment

The Jupyter ecosystem has three distinct production modes — pick before you start.

Single-user remote server

For one developer's remote box, jupyter lab with a token + reverse proxy:

bash
jupyter lab \
  --no-browser \
  --ip=127.0.0.1 \
  --port=8888 \
  --ServerApp.token="$(openssl rand -hex 32)" \
  --ServerApp.allow_origin='https://lab.example.com'

Output: server bound to localhost only; expose via SSH tunnel or a reverse proxy that adds TLS. Never expose 0.0.0.0 without TLS and a strong token.

Nginx fragment for proxy + WebSocket upgrade:

nginx
location / {
    proxy_pass http://127.0.0.1:8888;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

Output: WebSocket-aware proxy; Upgrade header is required — without it kernels can't talk to the browser.

Multi-user — JupyterHub

For shared infrastructure (university lab, research team), use JupyterHub rather than rolling per-user jupyter lab instances. JupyterHub provides:

  • Login authentication (PAM, OAuth, LDAP, Shibboleth)
  • Per-user notebook server spawning (LocalProcessSpawner, DockerSpawner, KubeSpawner)
  • Resource isolation per user (cgroups, container limits)
  • A central admin UI

Minimal install:

bash
pip install jupyterhub jupyterlab
npm install -g configurable-http-proxy

Output: jupyterhub on PATH. Generate a default config: jupyterhub --generate-config. Production deployments almost always run JupyterHub in Docker or Kubernetes — the jupyterhub/k8s-hub Helm chart is the standard path.

Containerised single-user — Docker

The community-maintained jupyter/datascience-notebook image is the reference for a containerised JupyterLab:

bash
docker run -p 8888:8888 \
  -v "$PWD":/home/jovyan/work \
  jupyter/datascience-notebook:latest

Output: JupyterLab on http://localhost:8888?token=<printed-on-stdout>. The jovyan user is the convention (named after Jupiter's moons). The bind mount maps the current directory to the in-container workspace.

For reproducible builds, fork the image, pin Python + library versions in a requirements.txt, and bake the kernel registration into the Dockerfile.

Performance tuning

Auto-reload for iterative development

python
%load_ext autoreload
%autoreload 2

Output: every imported module is re-imported on every cell execution. Saves the "restart kernel after every edit" loop — at the cost of a small per-cell overhead and occasional stale references.

Kernel startup time

ipykernel's default startup loads matplotlib's font cache and pandas type machinery — ~1-2 s. For a long-lived JupyterLab session this is invisible; for short-lived papermill runs it's ~50% of the total. To shave it:

  • Avoid from pandas import * at notebook top; import lazily inside the cell that needs pandas.
  • Pre-warm in a Docker base image with a one-time python -c "import pandas, matplotlib" build step.

Big-output cells

A cell that streams 100 MB of text to stdout will bog down JupyterLab — the frontend keeps the whole output in memory. Use tqdm for progress (one updating line) instead of print per row.

jupyter-cache for notebook re-execution

bash
pip install jupyter-cache
jcache notebook add notebook.ipynb
jcache project execute      # only re-executes cells whose inputs changed

Output: cells with unchanged source are skipped on re-execution — the canonical fast path for nbconvert-based publishing pipelines (Quarto, JupyterBook, MyST).

Version migration guide

Classic Notebook 6 → 7

The 7.0 release rewrote the classic Notebook UI on top of jupyter-server and JupyterLab components. The user-facing layout is similar; the extension API is entirely different. Extensions written for 6.x must be ported to 7.x — there is no shim. To stay on 6.x temporarily:

bash
pip install "notebook<7"

Output: classic notebook frozen on the 6.x line; security fixes still backported but no new features.

JupyterLab 3 → 4

JupyterLab 4 (2023) moved the build system from webpack to esbuild and pre-bundled extensions — most extensions no longer require a node build step at install time.

  • jupyter labextension install <name> (the pre-4.0 path) is gone; use pip install jupyterlab-<name> for the pip-distributed extension.
  • The CSS variable system was reorganised; custom themes need updating.
  • Old "source extension" projects need to be rebuilt as "prebuilt extensions".

nbformat v4 → v4.5

The on-disk schema added cell IDs (so cells can be referenced even after reordering). Tools that emit .ipynb (papermill, jupytext, Jupyter itself) emit v4.5; readers should accept both.

Python floor moves

Each Jupyter ecosystem release tracks the SPEC 0 timeline — Python ~3 years after release, NumPy ~2 years. As of late 2025 the active matrix is Python 3.10+; older Python pins force older Jupyter components.

Security considerations

Jupyter servers are remote-code-execution platforms by design — the threat model is more like SSH than like a CMS.

Authentication

  • Token (default) — random 48-char token printed at server start. Sufficient for SSH-tunnelled single-user usage. Never disable the token on a network-reachable port.
  • Passwordjupyter server password stores a hashed password in jupyter_server_config.json. Browser-friendly for single-user remote.
  • Identity providers — JupyterHub supports OAuth (GitHub, Google), LDAP, SAML, JWT. Production multi-user setups must use one of these, not the token.

Kernel sandboxing

The kernel runs arbitrary Python with the same OS privileges as the server process. A single-user server is therefore "exec as the user that started it". To isolate untrusted users:

  • Per-user containers — DockerSpawner / KubeSpawner. Each user gets a fresh container; kernel crash or fork-bomb doesn't affect others.
  • Resource limits--ResourceUseDisplay.mem_limit=4G shows a memory bar to the user; combine with cgroups for hard enforcement.
  • No-network spawners — drop the kernel's outbound network entirely for sensitive data.

Notebook trust

Notebooks store outputs that may include HTML and JavaScript. Jupyter treats notebooks as "untrusted" by default — JS in outputs is stripped on display. The trust state is per-signature; modifications invalidate the signature. Do not flip trust on for notebooks downloaded from the web.

Header hardening

For internet-facing JupyterHub or proxied Jupyter, set CSP and X-Frame-Options:

python
# jupyter_server_config.py
c.ServerApp.tornado_settings = {
    "headers": {
        "Content-Security-Policy": "frame-ancestors 'self'",
        "X-Content-Type-Options": "nosniff",
    }
}

Output: strict CSP; iframe-embedded JupyterLab requires explicit allowlisting.

Compatibility matrix

ComponentRecent stablePython floorNotes
jupyterlab4.x3.10Prebuilt extensions; esbuild
notebook7.x3.10Rewritten on top of jupyter-server
notebook (classic)6.5.x3.7Maintenance-only; pin notebook<7
jupyter-server2.x3.9Shared HTTP/WebSocket layer
ipykernel6.x3.9The Python kernel
ipython9.x3.11REPL; some Jupyter components still depend on it
nbformat5.x3.8On-disk schema (v4.5 cell IDs)
nbconvert7.x3.8Export to HTML/PDF/slides

Always install the components together — mixing jupyterlab 4.x with notebook 5.x will produce confusing extension-loading errors. pip install -U jupyterlab is usually enough to pull a consistent set.

Ecosystem integrations

  • VS Code — the Python extension's "Jupyter" feature runs .ipynb files using only ipykernel. Skip JupyterLab entirely if you prefer VS Code.
  • PyCharm Professional — native notebook editor; uses the project's Python interpreter as the kernel.
  • papermill — parametrised notebook execution. The standard CI-friendly path.
  • jupytext — pair .ipynb with .py / .md / .Rmd for diffable source.
  • nbstripout — git filter that strips outputs on commit.
  • jupyter-cache — incremental notebook re-execution for publishing pipelines.
  • nbvalpytest plugin that re-executes a notebook and compares outputs as a test.
  • voila — turn a notebook into a standalone web app (no code cells visible).
  • quarto — scientific publishing tool that ingests .ipynb and renders HTML/PDF/EPUB.
  • JupyterBook / MyST — multi-notebook book/site builders.
  • google-colab — Google's hosted Jupyter with free GPU; uses Jupyter's protocols but is a fork of the frontend.
  • kaggle-notebooks — Kaggle's hosted variant; similar protocol-level compatibility.

When NOT to use this

  • Production code paths. Notebooks are exploratory tools — not deployment artefacts. Extract the code into a .py module, write tests, and import the module from the notebook for prototyping. Running papermill in production is fine for reports, not for services.
  • Long-lived background jobs. A kernel pinned to a browser tab is not a job runner. Use Airflow, Prefect, or plain cron + a Python script.
  • Source-controlled multi-developer collaboration on the same file. .ipynb merge conflicts are a recurring source of pain even with jupytext and nbstripout. Pair with a per-feature notebook convention or use a real IDE.
  • Strict reproducibility. Cells can be executed out of order; "Restart kernel and run all" is the only reproducible mode and is easy to forget. For reproducibility-first workflows, consider marimo (cells form a DAG and re-run automatically).
  • Tight performance loops. The kernel's I/O round-trip adds ~1 ms per cell; that's invisible in interactive use but disqualifying for inner loops. Run hot code in .py files.

See also