UV: A Comprehensive Guide to the Future of Python Tooling

Python
Tooling
UV

A complete technical guide to UV, the blazing-fast Python package manager. Learn to install, configure, and manage projects, unifying pip, venv, and pipx into one simplified workflow, inspired by Corey Schafer’s tutorial.

Author

Nion M. Dransfeld

Published

September 12, 2025

The Python ecosystem, while powerful, has long been characterized by a fragmented toolchain. Developers typically juggle pip for package installation, venv for environment management, and pipx for command-line applications. This article introduces UV, a next-generation toolchain from Astral designed to consolidate this entire workflow into a single, cohesive, and blazing-fast binary written in Rust. This guide is heavily inspired by the excellent video tutorial, “Python Tutorial: UV - A Faster, All-in-One Package Manager to Replace Pip and Venv”, from Corey Schafer, which provides a practical walkthrough of UV’s capabilities. By the end of this guide, you will be able to install, configure, and manage a full Python project using UV, significantly streamlining your development process.

The Core Problem: Inefficiency and Lack of Reproducibility

The classic Python workflow presents two major challenges. First, inefficiency: pip can be slow, especially when resolving complex dependencies, and lacks a universal caching mechanism that works across all projects. Second, poor reproducibility: a standard requirements.txt file often fails to lock transitive (sub-dependency) versions, leading to the infamous “it works on my machine” problem. As developer Corey Schafer puts it, the goal of UV is ambitious and directly targets these issues: > “They want it to be a single tool that can replace PIP for installing packages, VENV or virtual ENV for creating and managing virtual environments, PIP tools for generating lock files, and even PIPX for installing and running Python tools.” — Corey Schafer [00:00:11]

The UV Workflow: A Step-by-Step Guide

UV replaces the multi-tool workflow with a single, coherent set of commands that manage the entire project lifecycle.

Step 1: Installation and Verification

First, install UV on your system. The methods are optimized for each major operating system and are quick to execute.

# macOS (via Homebrew)
brew install uv

# macOS and Linux (via curl)
curl -LsSf [https://astral.sh/uv/install.sh](https://astral.sh/uv/install.sh) | sh

# Windows (via PowerShell)
irm [https://astral.sh/uv/install.ps1](https://astral.sh/uv/install.ps1) | iex

Important Point 1: After installation, verify that the uv command is available in your shell’s PATH. You may need to restart your terminal.

Important Point 2: Run uv --version to confirm the installation was successful. Running uv with no arguments will display a helpful list of all available commands.

Step 2: Project Initialization and Dependency Management

With UV installed, you can bootstrap a project and manage its dependencies with just two commands.

# Initialize a new project
uv init my-new-app
cd my-new-app

# Add packages
uv add flask "requests==2.28.1"

Important Point 1: The uv init command automates several best practices. As Schafer notes, “UV automatically initializes a git repository for us, which is nice because most of us will want to track our code within version control anyway.” [07:10]. It also creates a .gitignore file, a pyproject.toml configuration, and a .python-version file.

Important Point 2: The uv add command intelligently handles multiple tasks. It automatically creates a .venv if one doesn’t exist, installs packages with extreme speed using a global cache, updates the pyproject.toml file with the new dependencies, and generates a uv.lock file for reproducible builds.

Step 3: Ensuring Reproducibility and Running Code

The lock file is the cornerstone of UV’s reproducibility, and the run command simplifies execution.

# On a new machine or in CI/CD, sync the environment from the lock file
uv sync

# Run a Python script within the managed environment
uv run python main.py

Important Point 1: The uv sync command guarantees that the exact versions of all dependencies specified in uv.lock are installed. This solves environment drift, a common source of bugs. Schafer explains, “So this ensures that your environment is perfectly reproducible… it helps to prevent the classic problem of it working on one machine and not working on another because of some small discrepancy somewhere.” [10:11]

Important Point 2: The uv run command executes any subsequent command within the project’s virtual environment, entirely removing the need for source .venv/bin/activate.

Practical Use Case: Global Tools with uv tool and uvx

UV’s utility extends beyond individual projects by integrating the functionality of pipx for managing global command-line tools.

Installing Global Tools

The uv tool subcommand allows you to install Python applications like linters or formatters system-wide, but in isolated environments to prevent conflicts.

# Install the Ruff linter and formatter globally
uv tool install ruff

Ephemeral Execution with uvx

One of UV’s most powerful features is uvx (a shortcut for uv tool run), which executes a tool without permanently installing it. This is perfect for one-off tasks.

# Format the current project with black without installing it
uvx black .

As Schafer highlights, this feature is incredibly efficient: “So that UVToolRun command installs it in a temporary environment, runs it and then cleans it up afterwards which is super useful and it does it all very quickly.” [23:16]

Key Takeaways

Here are the most important points to remember about UV.

  • Extreme Speed: Built in Rust, UV’s performance is a generational leap. Its smart global cache avoids repeated downloads, saving significant time and disk space across all your projects.
  • Unified Tooling: UV consolidates pip, venv, and pipx into one elegant interface. Commands like uvx allow you to run tools like Ruff or black ephemerally.
  • Guaranteed Reproducibility: The auto-generated uv.lock file captures the entire dependency graph, solving the “it works on my machine” problem for good.
  • Simplified Experience: By automating environment creation and eliminating the need for manual activation, UV provides a smoother, more intuitive developer experience.

Common Mistakes to Avoid

When transitioning to UV, developers might encounter these common pitfalls.

  • Manually Activating the Environment: A frequent mistake is running source .venv/bin/activate out of habit. With UV, you should use uv run to execute commands within the environment’s context. This avoids polluting your global shell.
  • Forgetting to Use uv sync: When cloning a project managed by UV, do not run pip install -r requirements.txt. The correct command is uv sync, which uses the uv.lock file to create a perfectly reproducible environment.
  • Manually Editing pyproject.toml for Dependencies: While possible, you should let UV manage the [project.dependencies] section. Always use uv add <package> and uv remove <package> to ensure the lock file is correctly updated in sync with your configuration.

Conclusion

UV is more than just a faster pip; it is a holistic rethinking of the Python development experience. By combining speed, a unified interface, and intelligent automation, it addresses long-standing points of friction in the ecosystem. As Corey Schafer aptly concludes, UV takes what “used to be separate tools like PIP, PIPX, and virtual environments, and making them feel naturally like they belonged as a single tool to begin with.” [24:40]. Adopting UV can significantly boost productivity, reduce environment-related errors, and modernize your entire Python workflow.

#Python #UV #Tooling #DeveloperExperience