notebook
notebook is the Jupyter Notebook application: a local web server plus a browser interface where you write code in cells, run them one at a time, and see output (tables, plots, HTML) right underneath. The Python process that runs your code is a separate kernel, so state survives between cells and you can re-run one cell without re-running the file. Version 7 is a rewrite: the interface is now built from JupyterLab 4 components and the backend is Jupyter Server, so what you install is essentially JupyterLab's engine wearing the classic document-centric layout. That change is the single most important fact about this package, because extensions written for Notebook 6 and earlier do not work in it.
Notebook 7 is the right pick when you want the classic one-document interface on top of maintained modern internals, and it is what most teaching material still assumes. If your extensions come from the Notebook 6 era, budget real migration time; if the classic layout is not the reason you are here, install jupyterlab instead and save a layer.
Use it if
- You want the classic one-notebook-per-tab interface rather than JupyterLab's multi-panel workspace, and your users get confused by the IDE layout; Notebook 7 exists specifically to keep that simpler surface alive on modern internals
- You are teaching or writing a tutorial where each learner opens one file, runs cells top to bottom, and should not be shown a file browser, terminal, and debugger at the same time
- You do exploratory work where you load an expensive dataset once and then iterate on transformations and plots for an hour without paying the load cost again
- You need the wider Jupyter platform underneath: kernels for R or Julia, jupyter-server extensions, and nbconvert to turn the result into HTML or a script
- You are on Notebook 6 with nbextensions you depend on (variable inspector, table of contents, spellcheck, the whole jupyter_contrib_nbextensions family). None of them load in Notebook 7; you have to find prebuilt JupyterLab equivalents or stay on the 6.5.x branch, which the maintainers describe as maintenance and security fixes only
- You actually want JupyterLab. Installing notebook pulls in jupyterlab 4.6 as a hard dependency anyway, so if the IDE layout suits you, install jupyterlab directly and skip the extra frontend
- Your notebooks live in git. The file format is JSON with execution counts and base64 output blobs inline, so every run produces a noisy diff and merge conflicts you cannot resolve by hand without nbstripout, nbdime, or jupytext bolted on
- You keep getting bitten by hidden state. Cells can be run in any order, so a notebook that works on your machine may not reproduce top to bottom, and deleted cells leave their variables alive in the kernel. Reactive notebooks like marimo make that class of bug impossible by design
- You are shipping production code. A notebook is a poor unit of deployment: no imports from it without extra tooling, no straightforward testing, no code review that reads well. Move logic into modules once it stops changing every five minutes
- The dependency pin is a problem for you: notebook 7.6.1 requires jupyterlab >=4.6.2,<4.7 and jupyter-server >=2.19,<3, so you cannot upgrade JupyterLab independently and a conflicting pin elsewhere in your environment can block the install outright
Setup reality
pip install notebook needs Python 3.10 or newer and pulls a real stack behind it: jupyterlab 4.6.x, jupyter-server 2.19+, jupyterlab-server, notebook-shim, jupyter-builder, and tornado. That is a few dozen megabytes and a handful of entry-point scripts, and because jupyterlab is pinned to <4.7 you lose the ability to bump JupyterLab on its own. Running jupyter notebook starts a server on 8888 and prints a URL with a one-time token; miss it and you have to run jupyter server list to get the token back. The kernel your notebook uses is whichever ipykernel is registered, not necessarily the environment you installed notebook into, which is the number one reason imports fail inside a notebook that work in the shell; fix it with python -m ipykernel install --user --name myenv. Configuration moved too: server settings now live in ~/.jupyter/jupyter_server_config.py under ServerApp rather than the old NotebookApp names. Exporting to HTML or PDF needs nbconvert installed separately, and PDF additionally needs a LaTeX toolchain or a headless browser.
Patterns
Install and start the notebook serverinstall-and-launch
pip install notebook
jupyter notebook
# start without opening a browser, on a fixed port
jupyter notebook --no-browser --port 8888The startup log prints a URL containing a one-time token; that token is the login. Notebook 7 also serves /lab from the same server because JupyterLab comes along as a dependency.
Find running servers, their tokens, and shut them downrecover-token-and-stop-server
jupyter server list
# http://localhost:8888/?token=ab12... :: /home/me/work
jupyter server stop 8888Use this when you closed the terminal and lost the token, or when port 8888 is taken by a server you forgot about. jupyter notebook list still works as an alias in Notebook 7.
Write a persistent server configurationgenerate-and-edit-config
jupyter server --generate-config
# creates ~/.jupyter/jupyter_server_config.py
# in that file:
c.ServerApp.ip = "127.0.0.1"
c.ServerApp.port = 8888
c.ServerApp.open_browser = False
c.ServerApp.root_dir = "/home/me/notebooks"Notebook 7 runs on Jupyter Server, so settings use the ServerApp prefix. Old guides using c.NotebookApp.notebook_dir and friends target Notebook 6 and are silently ignored or warned about.
Set a password so you stop copying tokenspassword-instead-of-token
jupyter server password
# Enter password: ...
# hashed password written to ~/.jupyter/jupyter_server_config.json
jupyter notebookOnce a password is set, the token prompt is replaced by a login form. Never combine a password with --ip 0.0.0.0 over plain HTTP; put it behind TLS or an SSH tunnel, because the kernel gives anyone who logs in arbitrary code execution as your user.
Serve at a subpath behind a reverse proxyremote-access-behind-proxy
jupyter notebook \
--no-browser \
--ip 127.0.0.1 \
--port 8888 \
--ServerApp.base_url=/jupyter/ \
--ServerApp.allow_remote_access=Truebase_url must match the proxy location and keep its trailing slash, or the frontend loads a blank page while requesting assets from the wrong path. The websocket route needs proxying too; an HTTP-only proxy config gives you a UI that connects to no kernel.
Point a notebook at the right virtual environmentregister-a-kernel
source .venv/bin/activate
pip install ipykernel
python -m ipykernel install --user --name myproj --display-name "Python (myproj)"
jupyter kernelspec listThis is the fix for "ModuleNotFoundError in the notebook but the import works in my shell". The kernel runs in the environment it was registered from, which is independent of the environment running the server. Remove stale ones with jupyter kernelspec uninstall myproj.
Run a notebook from the command lineexecute-notebook-headless
pip install nbconvert
jupyter nbconvert --to notebook --execute report.ipynb \
--output report-run.ipynb \
--ExecutePreprocessor.timeout=600Useful in CI to prove a notebook still runs top to bottom. The default per-cell timeout is 30 seconds, which almost any real data cell exceeds. For parameterized runs, papermill wraps this with input injection.
Convert a notebook to something shareableexport-to-html-or-script
jupyter nbconvert --to html report.ipynb
jupyter nbconvert --to html --no-input report.ipynb # outputs only
jupyter nbconvert --to script analysis.ipynb # analysis.pynbconvert is a separate install, not a dependency of notebook. PDF export additionally needs a LaTeX toolchain (or --to webpdf plus a headless browser), which is why it fails on a clean machine.
Keep outputs out of version controlstrip-outputs-for-git
jupyter nbconvert --ClearOutputPreprocessor.enabled=True \
--to notebook --inplace *.ipynb
# or automate it:
pip install nbstripout
nbstripout --install # adds a git filter in this repoOutputs are stored inline as JSON, including base64 images, so a single plot can add megabytes per commit and guarantee conflicts. Stripping them also prevents credentials printed in a cell from ending up in history.
Add extensions that actually work in Notebook 7install-extensions
pip install jupyterlab-git jupyterlab_execute_time
jupyter labextension list # prebuilt frontend extensions
jupyter server extension list # server-side extensionsNotebook 7 loads JupyterLab prebuilt extensions, not classic nbextensions. If a package's install instructions say jupyter nbextension enable, it targets Notebook 6 and will not appear in your interface.
Know the routes the server exposesnotebook-urls
http://localhost:8888/tree # file browser
http://localhost:8888/notebooks/foo.ipynb # single notebook, classic view
http://localhost:8888/edit/config.yaml # plain text editor
http://localhost:8888/terminals/1 # terminal
http://localhost:8888/lab # JupyterLab, same serverBookmarking /notebooks/<path> is the closest thing to the Notebook 6 experience. Because /lab is served by the same process, one running server can hand different users different interfaces.
Prove the notebook reproduces before you share itrestart-and-run-all
# In the UI: Kernel > Restart Kernel and Run All Cells
# Same check in CI:
jupyter nbconvert --to notebook --execute --inplace report.ipynb \
&& git diff --exit-code report.ipynbOut-of-order execution means a notebook that looks finished can depend on a variable from a cell you already deleted. A clean restart-and-run-all is the only evidence that the file works for the next person.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| jupyterlab | PyPI | You want the multi-panel IDE (file browser, terminals, debugger, side-by-side notebooks) instead of the classic single-document view; notebook installs it anyway. |
| marimo | PyPI | You want notebooks stored as plain Python files that diff cleanly in git, with a reactive execution model that removes stale-state bugs and can be served as an app. |
| nbclassic | PyPI | You need the literal Notebook 6 interface and its extension points on top of a maintained Jupyter Server, usually as a stopgap while migrating extensions. |