uv, from the makers of Ruff, reimplements pip's core functionality in Rust and wraps it in a genuinely unified project management tool ā replacing pip, venv, pip-tools, and pipx-style global tool installs with one consistent, dramatically faster interface. This lesson covers why it's rapidly becoming the default choice for new Python projects.
1The Same Correctness, a Dramatically Different Speed
uv's core dependency resolver solves the exact same problem pip's resolver does ā finding a consistent set of versions across an entire dependency tree satisfying every declared constraint ā but implemented in Rust, a compiled systems language, rather than pip's pure-Python implementation. For computationally-intensive work like constraint satisfaction across a large dependency graph, this implementation-language difference produces a genuinely dramatic real-world speed difference ā resolution and installation that might take pip real, noticeable time (seconds to, on a complex project, minutes) often completes with uv in a small fraction of a second to a couple of seconds.
This isn't a difference of degree that only matters for extremely large projects ā it changes actual day-to-day developer behavior. An operation fast enough to feel instantaneous gets run more freely and more often (adding a dependency, regenerating a lock file, spinning up a fresh environment) than one that requires a deliberate pause to wait for; the psychological and workflow difference between 'a few seconds' and 'a couple of minutes' for a routine, frequently-repeated operation compounds meaningfully over a team's collective time.
Critically, uv's speed advantage comes from *implementation*, not from cutting corners on correctness ā it performs the same genuine, rigorous dependency resolution pip's modern resolver does, generating the same kind of reproducible lock files covered in the Dependency Management lesson, just computed dramatically faster.
# Roughly equivalent operations, dramatically different speed characteristics:
$ time pip install -r requirements.txt # can take real, noticeable time
$ time uv pip install -r requirements.txt # often a small fraction of that timeSame rigorous resolution as pip ā implemented in Rust, dramatically faster
2Unifying Previously-Separate Tools Into One Interface
Before uv, a typical Python project's tooling required several separate tools, each with its own command syntax and its own configuration conventions: venv (or virtualenv) for creating an isolated environment, pip for installing dependencies into it, pip-tools for generating a pinned lock file from loose requirements, and often pyenv or a similar tool for managing which Python *version* is even available to use in the first place.
uv consolidates all of these into one consistent command-line interface: uv venv creates the virtual environment; uv add httpx both adds the dependency to pyproject.toml and regenerates the lock file in one step (a workflow that previously required manually editing pyproject.toml and separately re-running a lock-file generation tool); uv sync installs exactly what the lock file specifies; and uv python install 3.13 even manages *which Python interpreter versions* are available on the machine at all, a job previously requiring a separate tool entirely.
This unification is a genuine ergonomic improvement independent of the speed benefit ā a single tool with one consistent mental model and command syntax, rather than needing to remember which of four or five different tools handles which specific job, and how their configuration files and conventions interact (or occasionally conflict) with each other. It's the specific reason uv is frequently described as an 'all-in-one' Python project manager rather than merely 'a faster pip.'
$ uv venv # creates .venv (replaces python -m venv)
$ uv add httpx # adds + installs a dependency, updates pyproject.toml AND the lock file
$ uv sync # installs exactly what's in uv.lock (replaces pip install -r ...)
$ uv python install 3.13 # installs a specific Python VERSION itself, if neededOne tool replacing venv + pip + pip-tools + pyenv
3uv run: Environment Resolution Without Manual Activation
The Virtual Environment Best Practices lesson covered the traditional friction of manual venv activation ā a genuinely common source of 'wait, which Python am I actually running' confusion, especially across multiple terminal tabs or when switching between projects. uv run <command> sidesteps this entirely: it determines the correct environment for the current project (based on the pyproject.toml/uv.lock files present) and executes the given command directly inside that environment, with no dependency on whatever is or isn't currently activated in the calling shell.
This means uv run pytest, uv run python script.py, or uv run ruff check all reliably execute against the *correct* project environment every single time, regardless of shell state ā eliminating an entire, previously common category of 'why is this failing, oh, I forgot to activate the venv in this terminal tab' debugging detours. It's a genuine usability improvement built directly on top of uv's fast resolution and unified environment management: because uv already knows exactly which environment corresponds to the current project, and creating/syncing that environment is fast enough to be effectively free, uv run can simply ensure the environment is correct and use it, every time, without requiring the developer to manage that state manually themselves.
This specific capability ā a fast, correct, activation-free way to run commands in the right project environment ā is frequently cited as one of the most immediately, tangibly valuable parts of adopting uv day to day, independent of the underlying resolution-speed benchmarks that get more attention.
$ uv run pytest # runs pytest inside .venv, correctly, regardless of shell state
$ uv run python script.py
# No 'source .venv/bin/activate' needed -- uv resolves the right environment every timeAlways the correct environment ā no manual activation, no shell-state dependency
4Step-by-Step Breakdown
The same dependency resolution pip performs in seconds to minutes, uv often performs in a fraction of a second. That speed difference changes how people actually use their tools, not just how long they wait.
uv reimplements pip's resolver in Rust -- the SAME dependency resolution problem, solved dramatically faster.
Checkpoint: What is the fundamental reason uv can perform the same dependency resolution so much faster than pip?
- āuv's resolver is implemented in Rust, a compiled language, versus pip's implementation in pure Python
- āuv skips proper dependency resolution entirely, installing the first compatible version found
uv unifies venv creation, dependency installation, AND Python version management into one tool -- replacing several separate tools with one consistent interface.
uv run executes a command inside the project's environment automatically -- no manual activation step required, ever.
Checkpoint: Why does uv run pytest not require a prior "source .venv/bin/activate" step?
- āuv run automatically resolves and executes the command inside the project's correct environment, regardless of the current shell's activation state
- āuv run does not actually use a virtual environment at all
uv represents the modern all-in-one direction; Poetry is the other major all-in-one tool worth knowing, with different philosophical choices.
Resolve a Real Version Constraint. Finish resolve_version(): pick the lowest version that still satisfies the constraint.
Level Up š
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported (via server-side Python execution).
Fully supported (via server-side Python execution).
Fully supported (via server-side Python execution).
Fully supported (via server-side Python execution).
Best Practices
Default to uv for new Python projects, given its speed and unified tooling advantages
It replaces several previously-separate tools with one consistent interface, and its speed advantage is large enough to meaningfully change day-to-day development workflow, not just benchmark numbers.
Use uv run instead of manually activating a venv for running project commands
It guarantees the correct environment regardless of the current shell's activation state, eliminating a common, previously frequent source of "wrong Python" confusion.
Frequent Bugs
Continuing to manually activate a venv and run pip commands directly out of habit in a uv-managed project, missing the correctness and speed benefits of uv run and uv sync/add specifically designed for that project's lock-file-based workflow.
Adopt uv run and uv add/sync as the default workflow for a uv-managed project, rather than falling back to manual venv activation and pip commands out of old habit.
Real-World Examples
Onboarding a New Developer With uv in Under a Minute
A new team member clones a uv-managed repository and needs a fully working, correctly isolated environment set up as quickly as possible.
$ git clone https://github.com/acme/project.git
$ cd project
$ uv sync # creates .venv, installs exactly what uv.lock specifies -- typically seconds
$ uv run pytest # verifies the setup immediately, correct environment guaranteed