mailwal

It’s time to switch from pip to uv

Daily Python Projects

It’s time to switch from pip to uv

The same install takes pip eleven seconds and uv six hundredths of a second. Here is how to start using it today, on a real project.

If you have been writing Python for a while, your routine probably looks like this. Make a folder. Run python -m venv .venv. Activate it. Run pip install a few times. Write a requirements.txt, by hand or with pip freeze. Then tomorrow, forget to activate the environment and wonder for a minute why your import fails.

uv does all of that, and it is fast enough that you stop thinking about it at all.

By the end of this post you will know how to use uv in your Python projects. You will learn:

  • what uv is

  • why people are leaving pip for it,

  • and how to build a small working project with it starting from an empty folder.

Package tools are the part of software development that nobody sits down and teaches you, and also the part you touch every single day.

The reason people switch

Speed is what gets them to try it. I made a virtual environment and installed pandas, rich and requests, first with pip and then with uv, on the same machine.

The top two bars are pip, first with nothing cached and then again with everything already downloaded. The bottom two are uv doing the same job.

The interesting one is the last bar. The second time, uv finishes in six hundredths of a second, because it does not copy anything. It links the files from a cache it keeps on your disk. pip stays around eleven seconds either way, because it unpacks and copies every file again for every project.

That is the difference that makes people stay. Starting a new project stops being something you put off until the weekend.

Installing it

One line. On macOS or Linux:

curl -LsSf https://astral.sh/uv/install.sh | sh

On Windows, in PowerShell:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

If you would rather not pipe a script into your shell, pip install uv works too. Check it with uv --version.

Build something with it

Now the part you should actually type along with. We will make a small tool that reads a CSV of expenses and prints a summary table.

If you are using the terminal (or VS Code):

In case you use a terminal or an IDE such as VS Code which does not have uv integrated, you will have to open a terminal window and run:

uv init --no-package expenses
cd expenses

That will create a folder named “expenses” and create the uv configuration files inside that folder.

If you are using an IDE such as PyCharm:

PyCharm has uv integrated so, when you create a project in PyCharm, choose uv as the interpreter type.

The above is the equivalent of running uv init --no-package expenses in your computer terminal or VS Code terminal.

In either case you will end up with a folder (i.e., expenses) with a main.py, a README.md, a .python-version and a pyproject.toml. The --no-package is there to keep things simple. Without it, uv sets the project up to be built and published as a package, which you do not need for a tool you are writing for yourself.

Now add a library. We will add the rich library in our example, which is about printing tables that look good in a terminal.

uv add rich

Read that output, because four things happened from one command. uv picked a Python version. It created the virtual environment for you. It worked out which packages were needed and installed them. And it wrote your new dependency into pyproject.toml and into a new file called uv.lock.

You did not create a venv. You did not activate anything.

The three files uv keeps

Note that a .venv virtual environment is created by uv just like it does with pip. The folder contains an isolated Python interpreter and the Python packages we install (e.g., rich).

Difference with pip:

With pip, requirements.txt is whatever you remembered to write down. With uv, pyproject.toml holds what you asked for, and uv.lock holds exactly what you got, including the packages your packages depend on. The second file is the one that makes a project rebuild the same way next year.

Write the script and run it

Put a small expenses.csv next to main.py:

date,category,amount
2026-10-01,Groceries,62.40
2026-10-05,Rent,850.00
2026-10-06,Coffee,4.20

Then put this code in main.py:

import csv
from collections import defaultdict

from rich.console import Console
from rich.table import Table

totals = defaultdict(float)

with open("expenses.csv", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        totals[row["category"]] += float(row["amount"])

table = Table(title="Spending by category")
table.add_column("Category")
table.add_column("Total", justify="right")

for category, amount in sorted(totals.items(), key=lambda pair: -pair[1]):
    table.add_row(category, f"{amount:,.2f}")

Console().print(table)

And run it:

uv run main.py

That is the equivalent of doing python main.py in a pip environment. Here is the output:

uv run is the command you will use most. It runs your script inside the project’s own environment, whether or not anything is activated, and it checks the environment is up to date first. If a teammate added a package and you pulled their change, uv run installs it before your script starts.

Why the lock file matters

Here is the part that matters most. Delete the whole environment and ask for it back.

rm -rf .venv
uv sync

Six milliseconds, and the exact same versions as before. That is what you want when you come back to a project after six months, or when somebody clones your repository. Put pyproject.toml and uv.lock in git. Leave .venv out of it.

That’s it.

And If you already have pip projects…

You do not have to convert anything. uv can install a requirements.txt as it is:

uv pip install -r requirements.txt

Or you can move the project over properly, which takes one command:

uv add -r requirements.txt

That reads your requirements file, writes the packages into pyproject.toml, and creates the lock file. The old file can stay there or go.

The commands you actually need (the green ones are for uv)

There are more, but these eight cover almost everything. One extra worth knowing is uvx, which runs a command line tool without installing it into your project at all. uvx ruff check . downloads ruff, runs it, and leaves your project untouched.

Try it on one small project this week. Not your most important one. Make a new folder, run the two commands at the top of this post, and see how it feels when installing a package takes less time than reading the output.

If you learned something from this today, consider upgrading for the full experience: every weekly project with full source code, plus the complete archive. Since you read this far, I’d like to offer you 20% off the annual plan as a token of appreciation. Click below to get the discount:

Get 20% off

P.S. If you hit something that worked in pip and does not work in uv, reply and tell me what it was. I want to know where the rough edges are for people coming over.

Practice Python on ActiveSkill: solve up to 10 free exercises a day, follow a guided path, and keep improving between project posts - activeskill.dev

© 2026 Ardit Sulce
[email protected]