Converting Jupyter Notebooks to Python Scripts with uv
The problem: You have a .ipynb file and want to run it with uv — either to simplify execution, skip the Jupyter overhead, or make it portable and reproducible.
This may be obvious to experienced Python programmers out there, but I was today years old when I discovered that uv can run Jupyter notebooks. This is a big deal because sometimes people share code on GitHub open source projects, and you want to run it on your computer, but you don’t want all the overhead of running Jupyter notebooks. UV is a lot simpler.
The solution is to let uv handle Jupyter temporarily, convert the notebook, then never touch Jupyter again.
What is nbconvert?
nbconvert is a Jupyter tool that converts .ipynb files to other formats. It reads the notebook’s JSON structure — which contains cells, cell types, outputs, and metadata — and renders it into a target format.
The formats it supports include plain Python script (.py), HTML, PDF, Markdown, LaTeX, and RST. In this workflow we use --to script, which extracts only the code cells and writes them as a .py file. Markdown cells become comments. Outputs and cell metadata are stripped.
It is purely a format converter. It does not run your code unless you explicitly pass --execute.
What is nbconvert?
nbconvert is a Jupyter tool that converts .ipynb files to other formats. It reads the notebook’s JSON structure — which contains cells, cell types, outputs, and metadata — and renders it into a target format.
The formats it supports include plain Python script (.py), HTML, PDF, Markdown, LaTeX, and RST. In this workflow we use --to script, which extracts only the code cells and writes them as a .py file. Markdown cells become comments. Outputs and cell metadata are stripped.
It is purely a format converter. It does not run your code unless you explicitly pass --execute.
The Core Workflow
Step 1: Convert the notebook using uv
uv run --with jupyter jupyter nbconvert --to script notebook.ipynb
The --with jupyter flag tells uv to pull Jupyter into a temporary environment just for this command. Nothing is installed globally or persistently. Once the command finishes, Jupyter is gone.
This outputs notebook.py.
Step 2: Add inline dependency metadata
Open notebook.py and add this block at the very top, before any other code:
# /// script
# requires-python = ">=3.11"
# dependencies = ["pandas", "numpy"]
# ///
Replace the dependencies list with whatever your notebook actually uses.
Step 3: Run it
uv run notebook.py
uv reads the metadata block, creates an isolated environment, installs only the listed deps, and runs the script. No venv setup, no activation, no global state.
Why Not Install Jupyter First?
Installing Jupyter via pip install jupyter or even uv tool install jupyter just to run nbconvert once is the exact problem uv is designed to avoid. You end up with a persistent dependency that you only needed for a single command.
The --with flag is the right tool here. It gives you access to any package temporarily without leaving a trace.
If You Need to Keep the .ipynb Format
If you need the notebook to remain executable as a .ipynb — for example, to share with someone who uses Jupyter — you can execute it in place:
uv run --with jupyter jupyter nbconvert --to notebook --execute notebook.ipynb
This runs the notebook and writes the output back into the .ipynb file. Still no persistent Jupyter install required.