Running a Jupyter Notebook in a uv Python Environment

Discover how to launch Jupyter Notebooks with lightning-fast performance using the uv Python package manager.
Author

David Gwyer

Published

July 10, 2025

Recently, I had an idea for a new FastHTML app I wanted to develop around destructuring and analysing PDF documents (research papers more specifically), but my initial experiments did not go that well as I was not that familiar with many of the available Python libraries for reading and manipulating PDF documents.

So, naturally I reached for a Jupyter notebook to do some experimentation. But first I wanted to see if I could set it up to use uv as the Python environment manager. uv is my go to solution for almost all Python projects these days but I hadn’t used it to manage Python packages in a Jupyter notebook before, so this was a good excuse to try it out!

Setting up the Project

Create the project folder and cd into it:

mkdir my-notebook-project
cd my-notebook-project

This acts as a self-contained project for the Jupyter notebook, and Python environment libraries.

Create a pyproject.toml File

Next, create a pyproject.toml file in your project directory. The main purpose of this right now is to define what Python packages (dependencies) your project needs.

In your terminal create the file with touch pyproject.toml, and add the following content via VS Code, Cursor, or other editor of your choice:

[project]
name = "my-notebook-project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
  "jupyterlab",
  "ipykernel",
  "pandas",
  "matplotlib",
  "httpx"
]

Note: Swap out all instances of my-notebook-project with your own project name (if you have one).

These are just the dependencies I used in my project as the default Python libraries. Feel free to add your own. If you omit any libraries make sure you leave jupyterlab and ipykernel as the minimum requirements. Here’s a quick breakdown of what each dependency is for:

  • jupyterlab: Your interactive notebook IDE where you write and run Python code.
  • ipykernel: Enables JupyterLab to interact seamlessly with your Python environment.
  • pandas: Essential for data manipulation and analysis using DataFrames.
  • matplotlib: A core library for creating static, animated, and interactive plots.
  • httpx: A modern, async-capable HTTP client for making API requests.

Set Up the Python Environment

Now that you’ve specified the Python dependencies, it’s time to create an isolated Python environment and install these packages automatically using uv.

Run these commands in your terminal:

uv venv
uv sync

Here’s what’s happening:

  • uv venv creates a new, isolated Python virtual environment specifically for your project. This keeps things organized and prevents package conflicts.
  • uv sync automatically reads your pyproject.toml file and installs exactly the dependencies you’ve listed.

That’s it! Your environment is now ready for you to start creating and running Jupyter notebooks.

Your terminal output should look something like this:

$ uv venv
Using CPython 3.12.10
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate
$ uv sync
Resolved 107 packages in 30ms
Installed 102 packages in 166ms
 + anyio==4.9.0
 + argon2-cffi==25.1.0
 + argon2-cffi-bindings==2
 # (multiple lines hidden for brevity)
$ ls -a
.  ..  .venv  pyproject.toml  uv.lock

Register Your Environment as a Jupyter Kernel

To make your newly created uv Python environment available in JupyterLab, you’ll need to register it as a kernel. This allows you to select it when opening or creating notebooks. You have two ways to do this:

Option 1: Without Activating the uv Environment

Call Python directly from the environment’s path:

./.venv/bin/python -m ipykernel install --user --name=my-notebook-project --display-name "My Notebook"

This works because uv creates a standard Python virtual environment under .venv/. No activation or deactivation is required.

Option 2: With uv Environment Activation (Optional)

If you prefer to activate the environment before running commands:

source .venv/bin/activate
python -m ipykernel install --user --name=my-notebook-project --display-name "My Notebook"

Once you’re done, you can deactivate with:

deactivate

🔎 Tip: You can verify you’re using the correct environment with:

which python

Command Explanation

Regardless of how you run the command, here’s a breakdown of what it does:

Part Explanation
python Runs the Python interpreter. Use the one from your virtual environment (e.g. ./.venv/bin/python) to register the correct environment.
-m ipykernel Tells Python to run the ipykernel module as a script. This module handles Jupyter kernel registration.
install The subcommand for ipykernel to install (register) a new kernel.
--user Installs the kernel just for the current user (no need for admin privileges).
--name=my-notebook-project The internal identifier for the kernel. Used by Jupyter to distinguish it from others. It must be unique.
--display-name "My Notebook" The human-friendly name shown in the Jupyter interface when selecting a kernel. You can make this anything you want.

It basically tells Jupyter:

Register my current Python environment as a new kernel named my-notebook-project, and show it in the UI as ‘My Notebook’. Only install it for my user account.

If you ran this successfully, you should see this in your terminal (but with your own home directory instead):

$ ./.venv/bin/python -m ipykernel install --user --name=my-notebook-project --display-name "My Notebook"
Installed kernelspec my-notebook-project in /home/dgwyer/.local/share/jupyter/kernels/my-notebook-project

Launch JupyterLab

With your uv Python environment ready, and your kernel registered, you’re all set to launch JupyterLab:

uv run jupyter lab

From the terminal output copy the JupyterLab URL (or CTRL/CMD+Click) to open it in a browser.

Once JupyterLab is open:

  1. Create a new notebook.
  2. From the kernel dropdown in the upper right corner, select “My Notebook”.

You can test whether the environment is working correctly by adding this to a cell:

try:
    import matplotlib
    print("✅ matplotlib is available")
    print("Version:", matplotlib.__version__)
except ImportError:
    print("❌ matplotlib is NOT available")

You should see a success message.

Adding New Dependencies

You’re all set to use the Jupyter notebook with the dependencies you specified earlier. However, it’s common to need additional libraries as your project evolves. For instance, let’s say you want to add the seaborn library for advanced plotting. If we try to just use it out of the box then it will fail (as expected), as it’s not on our pyproject.toml dependency list.

We can easily rectify this though. Open a terminal (inside JupyterLab, go to File → New → Terminal) and run:

uv add seaborn

This single command will:

  • Automatically update your pyproject.toml.
  • Install the new package immediately.

No additional steps are needed! In your notebook, you can now import seaborn directly, there’s no need to restart JupyterLab. Let’s go back and rerun the cell we tried earlier. This time you should see a success message!

When to Use uv sync

A little note here on when you need to run uv sync. You’ll typically only need to run this if:

  • You’ve manually edited your pyproject.toml.
  • You’ve cloned a project from GitHub and want the exact same environment:
git clone your-project
cd your-project
uv venv
uv sync

If you’re just adding dependencies then you’re fine with just: uv add <package>. Nothing else is needed.

Final Tips

As your projects grow in complexity, a clean and consistent development environment becomes increasingly important. It’s easy to overlook the structure and tooling early on, but taking a bit of time to set things up properly will save you time down the line.

As we’ve seen, using uv for dependency management can offer blazing-fast installs. It handles dependency resolution efficiently and integrates smoothly with modern Python workflows.

Ultimately, the goal is to build a development workflow that’s both robust and easy to work with. The fewer distractions you face from your tooling, the more time and energy you can spend on actual problem-solving.