Register a Project Virtual Environment as a Named Jupyter Kernel
Register each project's virtual environment as a named ipykernel so Jupyter notebooks execute against the exact interpreter and dependency versions. Covers activation, ipykernel installation, kernelspec registration, verification via sys.executable, and recovery from broken kernels.
29 Aug 2026, 12:35 UTC

The Problem: Notebooks Running Against the Wrong Interpreter
You open a notebook, run import pandas, and get a version from your base Python installation instead of the project's pinned dependency. The notebook executes silently against whatever kernel is selected — often a global or default environment — so import resolution, type stubs, and runtime behavior drift from the reproducible environment defined in your requirements.txt or pyproject.toml. The fix is to register each project's virtual environment as a named ipykernel so the Jupyter server can offer it as a distinct kernel choice. Once registered, selecting that kernel guarantees the notebook runs with the exact interpreter and site-packages of that environment.
Desired Outcome
After completing this guide, your JupyterLab or classic Notebook interface will list a kernel named after your project (for example, Python (my-project)). Selecting it launches a kernel process whose sys.executable points inside the project's virtual environment, so every import resolves to the versions installed there. This works across JupyterLab, Notebook, and any front-end that speaks the Jupyter protocol.
Prerequisites
- Python installed and on
PATH(tested with 3.10–3.12). - A project environment created with
venv,virtualenv, orconda. The environment directory must exist and contain a workingpythonexecutable. - A Jupyter server installation reachable on your machine — this can be in a separate global environment, a user install, or a shared server. You do not need Jupyter installed inside the project environment.
- Permission to run
pip install ipykernelinside the target environment. On shared systems, you may need--useror a writable--prefixpath.
Procedure: Register the Kernel
- Activate the project environment.
# Linux / macOS (bash/zsh) source /path/to/project-env/bin/activate # Windows (PowerShell) C:\\path\\to\\project-env\\Scripts\\Activate.ps1 # conda conda activate my-projectVerify activation:
which python(orwhere pythonon Windows) should print a path inside the environment directory. - Install
ipykernelinto the environment.pip install ipykernelThis pulls the kernel machinery (including
ipython) into the project'ssite-packages. If you use conda, preferconda install -c conda-forge ipykernelto keep the conda solver consistent. - Register the kernelspec.
python -m ipykernel install --user --name my-project --display-name "Python (my-project)"Where to run: inside the activated environment, from any shell.
Permissions:--userwrites to your per-account Jupyter data directory (e.g.,~/.local/share/jupyter/kernelson Linux,~/Library/Jupyter/kernelson macOS,%APPDATA%\\jupyter\\kernelson Windows). No sudo/admin required.
Placeholders: replacemy-projectwith a short, unique kernel identifier (no spaces). The--display-nameis the human-readable label shown in the UI; quotes are required if it contains spaces.
Risk: if a kernel with the same--namealready exists, it will be overwritten silently. Runjupyter kernelspec listfirst to check.
What Just Happened: The Kernelspec File
The command creates a directory named after --name inside the user kernels directory. Inside that directory sits kernel.json, for example:
{
"argv": [
"/home/user/project-env/bin/python",
"-m",
"ipykernel_launcher",
"-f",
"{connection_file}"
],
"display_name": "Python (my-project)",
"language": "python",
"metadata": {
"debugger": true
}
}
The argv array records the absolute path to the environment's Python interpreter. If you later move or recreate the environment at a different path, the kernel will fail to start until you either re-register or edit this kernel.json to point at the new interpreter location.
Verification Checks
- List registered kernels.
jupyter kernelspec listConfirm
my-projectappears with a spec path under your user kernels directory. - Start Jupyter and select the kernel. Launch
jupyter laborjupyter notebookfrom any environment (it does not need to be the project environment). In the kernel selector, choose Python (my-project). - Run the interpreter check. In a new notebook cell:
import sys print(sys.executable) print(sys.version)The printed executable path must reside inside your project environment (e.g.,
/home/user/project-env/bin/python). The version string should match the environment's Python version. - Compare package versions. In the same notebook:
import pandas import numpy print(pandas.__version__, numpy.__version__)Run
pip list(orconda list) in a terminal with the environment activated. The versions must match exactly. If they differ, the notebook is still using a different environment.
Recovery and Maintenance
Kernel Fails to Start or Shows ModuleNotFoundError
- Run
jupyter kernelspec listand note the spec path for the problematic kernel. - Inspect its
kernel.json: verify the first element ofargvpoints to an existing Python executable.cat ~/.local/share/jupyter/kernels/my-project/kernel.json - If the interpreter is missing (environment deleted or moved), remove the stale spec:
jupyter kernelspec remove my-project - Recreate or relocate the environment, activate it, reinstall
ipykernel, and re-run the registration command.
Switching Kernels in a Running Notebook
Changing kernels via the UI restarts the kernel process. All in-memory variables, imports, and pending outputs are lost. Persist important results (write to disk, export notebook) before switching. There is no automatic state transfer between kernels.
Shared or Multi-User Servers
On a shared JupyterHub or server, --user installs kernels only for your account. To make a kernel available to all users or to bundle it with the project, use --prefix /path/to/shared/kernels (requires write access to that prefix) and ensure the Jupyter server's c.KernelSpecManager.kernel_spec_class or --kernelspec-dirs includes that path. The kernelspec then travels with the project directory if you place it under version control.
Conda Environments: A Note on Automatic Registration
When you install ipykernel into a conda environment (conda install ipykernel), conda's nb_conda_kernels extension (if present) may auto-register a kernelspec with a display name like Python [conda env:my-project]. Before running the manual registration step, check jupyter kernelspec list. If the conda kernel already exists and points at the correct interpreter, you can use it directly — no duplicate registration needed. If you prefer a custom display name, you can still register a second spec with a different --name; just keep both in sync if the environment path changes.
Limitations and Gotchas
- Environment path stability: Kernelspecs store absolute interpreter paths. Moving, renaming, or deleting the virtual environment breaks the kernel. Keep environment paths stable or script re-registration as part of your environment setup.
- Version drift:
ipykernelCLI flags and default data directories can change between releases. Runpython -m ipykernel install --helpto confirm flags for your version before scripting. - Multiple Python versions: If you maintain environments for different Python versions (e.g., 3.10 and 3.11), give each kernel a distinct
--namethat includes the version (e.g.,my-project-py310) to avoid collisions. - No rollback for registration: The registration command writes files; there is no built-in undo besides
jupyter kernelspec remove. Treat it as a state-changing operation.
Quick Diagnostic Checklist
| Symptom | Likely Cause | Action |
|---|---|---|
| Kernel not listed in UI | Registration failed or wrong kernels directory | Run jupyter kernelspec list; check kernel.json exists |
| Kernel starts but imports wrong package versions | argv points to wrong interpreter | Edit kernel.json or re-register from correct environment |
ModuleNotFoundError for installed packages | Environment missing packages or kernel uses base Python | Verify sys.executable in notebook; reinstall packages in that environment |
| Dead kernel on start | Interpreter path in kernel.json no longer exists | Remove spec, recreate environment, re-register |
Final Verification
After any change, repeat the verification steps: list kernels, start a notebook on the target kernel, print sys.executable, and compare package versions against pip list from the activated environment. When all three match, the notebook is reliably bound to the project's dependency set.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.