
Python has long relied on pip
as its standard package manager, but a
blazing-fast alternative is now changing the landscape.
uv is a Rust-based package manager that aims to transform Python dependency management with unmatched performance and simplicity.
In this guide, you will learn everything you need to know about uv and how to smoothly transition from the traditional pip ecosystem.
Let's get started!
What is uv?
uv is a high-performance Python package and project manager written in Rust. It was developed by Astral (the company behind the popular Ruff linter), and is designed to be the comprehensive solution for Python package management.
With uv, you can replace a wide range of traditional tools in your workflow, such as:
pip
for installing packages.pip-tools
for dependency locking.virtualenv
/venv
for environment management.pyenv
for managing Python versions.pipx
for installing CLI tools.poetry
for project configuration and publishing.twine
for distributing packages.
Thanks to its Rust-based roots, uv performs operations 10-100 times faster than these traditional Python tools, and this increase in speed is noticeable even in small projects.

uv also embraces modern packaging standards. It uses pyproject.toml
for
configuration and introduces a reliable lock file that ensures consistent
environments across systems.
Before we explore uv in detail, let's quickly recap the current Python landscape for package management.
Traditional Python Package Approach: pip
and virtualenv
The traditional Python package management workflow relies on a fragmented set of tools, each handling a specific piece of the puzzle.
It typically begins with installing Python, either via system package managers or by downloading it from the official website.
From there, you might use tools like venv
or virtualenv
to create isolated
environments, followed by pip
to install packages. Dependency tracking is
often manual or handled through add-ons like pip-tools
.
A typical workflow with pip
and virtualenv
might look like this:
# Create a virtual environment python -m venv .venv # Activate the environment source .venv/bin/activate # Install packages pip install django requests # Record dependencies pip freeze > requirements.txt
While this workflow is well-known and widely used, it involves multiple steps and tools, each with its own syntax and quirks. You must remember to activate environments, manage dependencies manually, and juggle a variety of commands.
This is precisely the pain point uv aims to solve by streamlining the entire process into a faster and more cohesive experience.
Installing uv
Getting started with uv is quick and straightforward, with support across all major operating systems. You can follow the official uv installation guide, or use one of the commands below.
On Linux and macOS, run:
curl -LsSf https://astral.sh/uv/install.sh | sh
On Windows, use PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
After installation, confirm that it's working by checking the version:
uv --version
uv 0.7.3
To update uv later, simply run:
uv self update
This will fetch and install the latest version automatically:
info: Checking for updates... success: Upgraded uv from v0.6.13 to v0.7.3! https://github.com/astral-sh/uv/releases/tag/0.7.3
The easiest way to begin using uv is to replace the tools you already rely on. Since uv is designed as a drop-in replacement, you can take advantage of its performance and simplicity without overhauling your current workflow.
Let's look at how that works in practice.
Managing Virtual Environments with uv for Python
uv can serve as a direct replacement for tools like virtualenv
and venv
to
create isolated Python environments.
Previously, you might run:
python -m venv .venv
With uv, the equivalent is:
uv venv # uses .venv by default
By default, this creates a virtual environment in .venv
, but you can specify a
custom path if needed:
uv venv <path/to/environment>
After running the command, uv provides a clear summary showing which Python interpreter was used, where the environment was created, and how to activate it in your shell:
Using CPython 3.13.2 interpreter at: /home/ayo/.local/share/mise/installs/python/3.13.2/bin/python Creating virtual environment at: .venv Activate with: source .venv/bin/activate.fish
You can also require that a specific version of Python is used:
uv venv --python 3.11
If the version isn't already installed, uv will fetch and install it for you automatically.
In practice, uv's environment creation is incredibly fast. In my tests, it was
roughly 200x faster than venv
:

Replacing Pip with uv for Dependency Management
uv provides a pip
-compatible interface for managing your project dependencies.
You only need to prefix specific pip
commands with uv
. For example, you can
install dependencies with:
uv pip install flask requests

There's no need to activate a virtual environment beforehand, as uv automatically detects and uses the nearest environment in your current or parent directory.
If no environment is found, it will prompt you to create one or suggest using
the --system
flag to install it globally:

Installing dependencies from existing project files works the same way:
uv pip install -r requirements.txt
uv pip install -r pyproject.toml
If you're using pip-tools to compile
requirements.txt
from a requirements.in
file, uv provides a much faster
alternative:
pip-compile requirements.in -o requirements.txt
With the uv equivalent:
uv pip compile requirements.in -o requirements.txt
I experienced a ~150x speedup over pip-compile
:

Removing dependencies is also straightforward with:
uv pip uninstall flask
Managing Python Versions with uv
One of uv's key advantages is that it doesn't rely on Python to run. Instead, it automatically detects existing Python installations and uses them for any Python-specific tasks.
If a project requires a version of Python that isn't already installed, uv will also download and manage it for you.
You can install Python versions directly like this:
uv python install # the latest version uv python install 3.13 # a specific version uv python install 3.13 3.12 # multiple versions
To check which versions are available on your system, run:
uv python list --only-installed
This lists all Python versions installed by uv, as well as any others already on your system, regardless of how they were installed:
cpython-3.13.2-linux-x86_64-gnu /home/ayo/.local/share/mise/installs/python/3.13.2/bin/python3.13 cpython-3.13.2-linux-x86_64-gnu /home/ayo/.local/share/mise/installs/python/3.13.2/bin/python3 -> python3.13 cpython-3.13.2-linux-x86_64-gnu /home/ayo/.local/share/mise/installs/python/3.13.2/bin/python -> python3.13 cpython-3.12.10-linux-x86_64-gnu /home/ayo/.local/share/uv/python/cpython-3.12.10-linux-x86_64-gnu/bin/python3.12 cpython-3.12.3-linux-x86_64-gnu /usr/bin/python3.12 cpython-3.12.3-linux-x86_64-gnu /usr/bin/python3 -> python3.12 cpython-3.11.12-linux-x86_64-gnu /home/ayo/.local/share/uv/python/cpython-3.11.12-linux-x86_64-gnu/bin/python3.11
With uv, you don't need to install Python ahead of time. If a command requires a
version you don't yet have, uv will fetch and install it automatically before
proceeding. This on-demand behavior eliminates the need for separate tools like
pyenv
.
Simplifying Tasks with uv
So far, I've focused on how uv can serve as a faster, drop-in replacement for tools you're already using, allowing you to gain performance benefits with minimal disruption.
But uv also introduces an alternative, more modern workflow that simplifies many tasks and goes beyond what traditional tools offer.
In the next sections, we'll explore some of these new capabilities.
Creating and Managing Python Projects with uv
One of uv's core goals is to manage the entire lifecycle of a Python project, from creating the project itself, to managing its dependencies, running commands or scripts, and even preparing it for distribution.
To start a new project, run:
uv init <project>
By default, this sets up an application-style project. To create a library project instead, use:
uv init --lib <project>
An initialized application project has the following structure:
. ├── .git ├── .gitignore ├── main.py ├── pyproject.toml ├── .python-version └── README.md
uv sets up version control with Git, includes pyproject.toml
for project
metadata and dependencies, and creates a basic script (main.py
) along with a
.python-version
file. It's ready to run out of the box.
Execute the script with:
uv run main.py
The first time you run this, uv will select the appropriate Python version, create a virtual environment, and then execute the script:
Using CPython 3.12.10 Creating virtual environment at: .venv Hello from example-project
At this point, uv generates a uv.lock
file, which records the full, resolved
dependency graph — ensuring consistent environments across different machines.
While pyproject.toml
defines intended dependencies (like requirements.in
),
uv.lock
captures the exact installed versions, effectively replacing
requirements.txt
for reproducibility.
Managing Dependencies to a uv Project
It's simple to add dependencies to a uv project. To add a package, use:
uv add requests

For development dependencies or tools, append the --dev
flag:
uv add --dev black
These changes are reflected in your pyproject.toml
:
# pyproject.toml . . . dependencies = [ "requests>=2.32.3", ] [dependency-groups] dev = [ "black>=25.1.0", ]
You can create custom dependency groups using the --group
flag:
uv add --group tools black uv add --group production gunicorn uv add --group dev pytest # same as uv add --dev
Resulting in:
[dependency-groups] dev = [ "pytest>=8.3.5", ] production = [ "gunicorn>=23.0.0", ] tools = [ "black>=25.1.0", ]
This structure makes it easy to install only the dependencies needed for a given environment. For example, to install just the base and production dependencies, run:
uv sync --no-group dev --no-group tools --group prod
Dependencies are always installed into the project's virtual environment, so there's no need to activate it manually. Once installed, you can run any tool using:
uv run <tool>
As in:
uv run pytest
This finds the tool version in your project's virtual environment and executes it:

uv also provides a tools interface for working with tools that aren't tied to a specific project:
uv tool run <tool> # Same as uvx <tool>
In this case, the tool and its dependencies are installed in a temporary virtual environment and executed accordingly. If you use the tool regularly, you can install it for easier access:
uv tool install <tool>
Upgrading and Removing Dependencies
uv provides straightforward commands for updating and removing packages as your project evolves. Here's how to upgrade a specific package to its latest version:
uv add --upgrade requests
This command updates the package and refreshes the lock file to ensure consistent environments across your team.
Removing packages is equally simple:
uv remove requests
uv will clean up the pyproject.toml
, remove unneeded transitive dependencies,
and regenerate the uv.lock
file automatically.
Migration Guide: From Pip to uv
Switching an existing project from Pip to uv is quite straightforward. Below is a quick reference table showing how common pip commands map to their uv equivalents:
Pip Command | uv Equivalent | Description |
---|---|---|
python -m venv .venv | uv venv | Creates a virtual environment |
pip install package | uv add package | Installs a package and updates project files |
pip install -r requirements.txt | uv pip install -r requirements.txt | Installs from requirements file |
pip freeze > requirements.txt | uv export -o requirements.txt | Exports dependencies |
pip list | uv pip list | Lists installed packages |
pip uninstall package | uv remove package | Removes a package |
If your project currently uses pip
and requirements.txt
, you can migrate it
to uv in just a few steps.
-
Initialize uv in the existing project directory:
Shelluv init .
This creates a
pyproject.toml
file and sets up the project structure, without replacing any existing files. -
Remove the old virtual environment:
Shellrm -rf .venv
-
Install dependencies from
requirements.txt
:Shelluv add -r requirements.txt
This installs the dependencies listed in your
requirements.txt
file in a virtual environment, and updates thepyproject.yml
anduv.lock
files accordingly. -
Create a new uv-managed environment:
Shelluv sync
-
Verify that everything works — for example (assuming you have a Django project):
Shelluv run manage.py migrate
Shelluv run manage.py runserver

Now your project should be fully migrated to uv with the same functionality as before, but now with uv's performance advantages.
Wrapping Up
By unifying the roles of multiple tools into one high-performance system, uv eliminates much of the friction developers have long dealt with.
Its speed alone is a compelling reason to adopt it, but uv's streamlined workflow and modern packaging standards make it even more appealing. For most projects, the transition is simple and the productivity gains are immediate.
uv's development is a strong signal of where the broader Python ecosystem is headed. Now is an ideal time to adopt this tool built for the future.
Thanks for reading!
Wondering what you can do next?
Finished this article? Here are a few more things you can do:
- Subscribe to our Python Wizardry newsletter and never miss an article again.
- Start monitoring your Python app with AppSignal.
- Share this article on social media
Most popular Python articles
An Introduction to Flask-SQLAlchemy in Python
In this article, we'll introduce SQLAlchemy and Flask-SQLAlchemy, highlighting their key features.
See moreMonitor the Performance of Your Python Flask Application with AppSignal
Let's use AppSignal to monitor and improve the performance of your Flask applications.
See moreFind and Fix N+1 Queries in Django Using AppSignal
We'll track the N+1 query problem in a Django app and fix it using AppSignal.
See more

Damilola Olatunji
Damilola is a freelance technical writer and software developer based in Lagos, Nigeria. He specializes in JavaScript and Node.js, and aims to deliver concise and practical articles for developers. When not writing or coding, he enjoys reading, playing games, and traveling.
All articles by Damilola OlatunjiBecome our next author!
AppSignal monitors your apps
AppSignal provides insights for Ruby, Rails, Elixir, Phoenix, Node.js, Express and many other frameworks and libraries. We are located in beautiful Amsterdam. We love stroopwafels. If you do too, let us know. We might send you some!
