pip is the de facto standard package manager for Python, but uv is a newer, Rust-based alternative that promises faster installation and dependency resolution.

Here’s uv in action, installing a common web framework and its dependencies:

$ uv install fastapi uvicorn

This single command does what pip install fastapi uvicorn would do, but uv typically completes this much faster.

Let’s break down why uv is so much quicker and what mental model you need to understand it.

The core problem uv solves is the quadratic complexity of dependency resolution in pip. When you install a package, pip recursively checks all its dependencies, and then their dependencies, and so on. If you have many packages, or packages with complex dependency graphs, this process can become incredibly slow. pip essentially has to backtrack and re-evaluate choices many times.

uv tackles this by using a much more efficient algorithm. It’s built in Rust, which allows for low-level memory management and concurrency that are harder to achieve in Python. More importantly, uv uses a technique called "satisfiability modulo theories" (SMT) solvers, specifically a variant tailored for dependency resolution. Instead of a brute-force, trial-and-error approach, uv models the entire dependency graph as a set of logical constraints. It then uses a highly optimized solver to find a single consistent set of package versions that satisfies all constraints simultaneously. This avoids the extensive backtracking and re-computation that plagues pip.

Consider the internal state uv maintains. When you run uv sync, it reads your requirements.txt (or pyproject.toml) and produces a uv.lock file. This lock file isn’t just a list of installed packages; it’s a deterministic snapshot of the exact versions and their resolved dependencies. uv prioritizes reading and updating this lock file. If you run uv sync and a lock file exists, uv can often determine what’s needed without even querying the package index, dramatically speeding up subsequent installs. It’s like having a pre-computed solution for your dependency graph.

The key levers you control are primarily how you specify your dependencies:

  • requirements.txt: The traditional way. uv can read and write these files.
  • pyproject.toml: The modern standard, using PEP 582 or poetry/pdm formats. uv integrates with these, allowing you to manage dependencies defined in your project’s build configuration.
  • Direct Installation: uv install fastapi uvicorn installs directly from PyPI.
  • From VCS: uv install git+https://github.com/user/repo.git@branch
  • From local paths: uv install ./my_local_package

uv also introduces the concept of "virtual environments" that are managed by uv itself. You don’t explicitly create a venv or conda environment in the traditional sense. Instead, uv manages a shared cache of installed packages and can create isolated environments on demand, linking to these cached packages. This is often faster and more space-efficient than creating full, independent virtual environments for every project.

When you run uv add fastapi, uv will not only install fastapi and its dependencies but also update your pyproject.toml file to include fastapi under the [project.dependencies] section. It intelligently determines the correct version specifier (e.g., fastapi = "^0.100.0") based on what it resolved. This "add" command is a significant quality-of-life improvement over manually editing pyproject.toml or requirements.txt after a pip install.

The most surprising thing about uv’s performance is not just the speed of initial installation, but the speed of reproducibility. When you have a lock file, uv can often install dependencies in seconds, even for very large projects, because it’s essentially just verifying and linking existing artifacts rather than re-resolving the entire graph.

The next hurdle you’ll encounter is understanding how uv handles different dependency groups (e.g., dev-dependencies, test-dependencies) and how it interacts with build backends like setuptools or hatchling.

Want structured learning?

Take the full Pip course →