uv: The Fast Python Package Manager Replacing pip in 2026

Introduction

Python package management has long been a point of frustration for developers. Between pip, virtualenv, pip-tools, pyenv, and poetry, the ecosystem became fragmented and slow. In 2024, Astral — the team behind the popular ruff linter — released uv, a blazing-fast Python package manager written in Rust that aims to replace them all.

By 2026, uv has become the de-facto standard for Python dependency management in new projects. It's 10–100x faster than pip, handles virtual environments automatically, and provides a unified toolchain from Python version management to dependency locking.

In this guide, you'll learn everything you need to start using uv in your Python projects, including FastAPI and Django applications.

🔗 Related: Building RESTful APIs with FastAPI: Best Practices and Patterns

Why Python Package Management Has Always Been Painful

For years, the typical Python project setup required multiple tools:

  • pyenv to manage Python versions
  • virtualenv or venv to create isolated environments
  • pip to install packages
  • pip-tools or poetry to lock dependencies
  • pip-compile to generate reproducible requirements.txt files

Each tool had its own configuration, its own quirks, and its own performance bottlenecks. pip is written in Python itself, which means it has to bootstrap Python before it can do anything. On large projects, pip install could take minutes.

Poetry improved the experience significantly, but it introduced its own complexity and was still noticeably slow.

uv solves all of this with a single, Rust-powered binary that handles the entire workflow.

What is uv?

uv is a Python package manager and project manager built by Astral. Under the hood, it's written in Rust and uses a dependency resolver based on PubGrub — the same algorithm used by Dart's package manager.

Key capabilities:

  • Install Python packages (drop-in replacement for pip)
  • Create and manage virtual environments (replacement for virtualenv)
  • Lock dependencies (replacement for pip-tools)
  • Manage Python versions (replacement for pyenv)
  • Run scripts with inline dependencies (replacement for pipx/manual venvs)
  • Manage monorepo workspaces

Performance benchmarks from Astral's own testing show uv is:

  • ~8x faster than pip for cold installs
  • ~80x faster than pip with a warm cache

This is transformative for CI/CD pipelines where install time directly affects build minutes and costs.

Installing uv

uv provides a standalone installer that doesn't require Python to be installed first.

macOS and Linux

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

Windows

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

Via pip (if you already have Python)

pip install uv

Verify Installation

uv --version
# uv 0.5.x (or similar)

Shell Completion

# bash
echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc

# zsh
echo 'eval "$(uv generate-shell-completion zsh)"' >> ~/.zshrc

uv Basics: Virtual Environments and Installing Packages

Creating a Virtual Environment

# Create a .venv in the current directory
uv venv

# Create with a specific Python version
uv venv --python 3.12

# Create at a custom path
uv venv ./my-env

Activating the Environment

# macOS/Linux
source .venv/bin/activate

# Windows
.venv\Scripts\activate

Installing Packages

# Install a package
uv pip install fastapi

# Install multiple packages
uv pip install fastapi uvicorn sqlalchemy

# Install from requirements.txt
uv pip install -r requirements.txt

# Install with extras
uv pip install "fastapi[all]"

# Install a specific version
uv pip install "fastapi==0.115.0"

The uv pip Command

All pip subcommands work through uv pip:

uv pip install <package>
uv pip uninstall <package>
uv pip list
uv pip show fastapi
uv pip freeze > requirements.txt
uv pip compile requirements.in -o requirements.txt

Managing Projects with uv init and pyproject.toml

Modern Python projects use pyproject.toml as a single source of truth for project metadata, dependencies, and tooling configuration. uv embraces this standard fully.

Initializing a New Project

# Create a new project
uv init my-api
cd my-api

This generates:

my-api/
├── .python-version   # Pinned Python version
├── .venv/            # Virtual environment (auto-created)
├── pyproject.toml    # Project config and dependencies
├── README.md
└── src/
    └── my_api/
        └── __init__.py

The pyproject.toml File

[project]
name = "my-api"
version = "0.1.0"
description = "My FastAPI project"
requires-python = ">=3.12"
dependencies = []

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Adding Dependencies

# Add a runtime dependency
uv add fastapi uvicorn

# Add a development dependency
uv add --dev pytest ruff mypy

# Add with version constraints
uv add "sqlalchemy>=2.0"

# Remove a dependency
uv remove requests

After running uv add, the pyproject.toml is automatically updated:

[project]
dependencies = [
    "fastapi>=0.115.0",
    "uvicorn>=0.32.0",
    "sqlalchemy>=2.0.0",
]

[tool.uv]
dev-dependencies = [
    "pytest>=8.0.0",
    "ruff>=0.8.0",
    "mypy>=1.11.0",
]

The uv.lock File: Reproducible Environments

When you run uv add or uv sync, uv creates a uv.lock file in your project root. This lock file pins the exact versions of every package in your dependency tree — including transitive dependencies.

# Sync your environment to match uv.lock
uv sync

# Sync including dev dependencies (default)
uv sync --dev

# Sync only production dependencies
uv sync --no-dev

# Update all dependencies to latest compatible versions
uv lock --upgrade

# Upgrade a specific package
uv lock --upgrade-package fastapi

Always commit uv.lock to version control. This ensures that every developer on your team, and every CI run, gets exactly the same package versions.

How uv.lock Differs from requirements.txt

Featurerequirements.txtuv.lock
Human-readableYesYes
Includes transitive depsNo (unless pip freeze)Yes
Cross-platform safePartialYes (platform markers)
Managed automaticallyNoYes
Conflict detectionNoYes

uv Workspaces: Managing Monorepos

If you have a monorepo with multiple Python packages, uv workspaces let you manage them as a unified project with shared dependencies.

# Root pyproject.toml
[tool.uv.workspace]
members = ["packages/*", "apps/*"]
my-monorepo/
├── pyproject.toml         # Root workspace config
├── uv.lock                # Single shared lockfile
├── packages/
│   ├── core/
│   │   └── pyproject.toml
│   └── utils/
│       └── pyproject.toml
└── apps/
    └── api/
        └── pyproject.toml
# Run a command in a specific workspace member
uv run --package api python -m uvicorn main:app

# Sync all workspace members
uv sync --all-packages

# Add a cross-workspace dependency
uv add --package api core

Running Scripts with uv run

One of uv's most powerful features is the ability to run Python scripts with inline dependencies, without manually creating a virtual environment first.

Basic Usage

# Run a script using the project's virtual environment
uv run python main.py

# Run a module
uv run python -m pytest

# Run a tool (like a CLI app)
uv run ruff check .
uv run mypy .

Inline Script Dependencies

You can embed dependency requirements directly in a script file using PEP 723 syntax:

# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "httpx",
#   "rich",
# ]
# ///

import httpx
from rich import print

response = httpx.get("https://api.github.com/repos/astral-sh/uv")
print(response.json()["stargazers_count"])
# Run it — uv installs dependencies automatically in an isolated env
uv run fetch_stars.py

This replaces the common pattern of creating a throwaway virtual environment for one-off scripts.

Migrating from pip, pip-tools, and Poetry to uv

From pip + requirements.txt

If you have an existing requirements.txt:

# Install from existing requirements.txt (no change needed)
uv pip install -r requirements.txt

# Convert to a proper project
uv init
uv add $(cat requirements.txt | grep -v '^#' | tr '\n' ' ')

From pip-tools (requirements.in → requirements.txt)

# Compile is now handled by uv pip compile
uv pip compile requirements.in -o requirements.txt

# Or better yet, migrate to uv's native project management
uv init
uv add -r requirements.in

From Poetry

uv can import a Poetry project's pyproject.toml directly in most cases, since both use the same standard format:

# In your existing Poetry project
uv sync  # uv reads [tool.poetry.dependencies] as a fallback

# Fully migrate: export from Poetry first
poetry export -f requirements.txt --output requirements.txt
uv init --name $(cat pyproject.toml | grep "^name" | cut -d'"' -f2)
uv add -r requirements.txt

For most projects, the migration is as simple as replacing poetry run with uv run and poetry install with uv sync.

uv in CI/CD: GitHub Actions Integration

uv is extremely fast in CI/CD environments because of its aggressive caching. Here's how to integrate it into a GitHub Actions workflow:

# .github/workflows/test.yml
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v4
        with:
          version: "latest"
          enable-cache: true

      - name: Set up Python
        run: uv python install

      - name: Install dependencies
        run: uv sync --frozen

      - name: Run tests
        run: uv run pytest

      - name: Lint
        run: uv run ruff check .

      - name: Type check
        run: uv run mypy .

Key CI/CD Tips

  • --frozen: Use uv sync --frozen in CI to ensure the lock file is respected and never automatically updated.
  • enable-cache: true: The setup-uv action caches the uv cache directory, making subsequent runs significantly faster.
  • No Python pre-install needed: uv manages Python itself, so you don't need actions/setup-python.

🔗 See also: Setting Up CI/CD Pipelines with GitHub Actions for Django and FastAPI

uv with FastAPI and Django Projects

Setting Up a FastAPI Project with uv

# Initialize the project
uv init fastapi-app
cd fastapi-app

# Add dependencies
uv add fastapi "uvicorn[standard]" sqlalchemy asyncpg alembic pydantic-settings

# Add development dependencies
uv add --dev pytest pytest-asyncio httpx ruff mypy

# Run the development server
uv run uvicorn app.main:app --reload

Your pyproject.toml:

[project]
name = "fastapi-app"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "fastapi>=0.115.0",
    "uvicorn[standard]>=0.32.0",
    "sqlalchemy>=2.0.0",
    "asyncpg>=0.30.0",
    "alembic>=1.14.0",
    "pydantic-settings>=2.6.0",
]

[tool.uv]
dev-dependencies = [
    "pytest>=8.3.0",
    "pytest-asyncio>=0.24.0",
    "httpx>=0.28.0",
    "ruff>=0.8.0",
    "mypy>=1.13.0",
]

Setting Up a Django Project with uv

# Initialize
uv init django-app
cd django-app

# Add dependencies
uv add django djangorestframework psycopg2-binary python-decouple

# Add dev dependencies
uv add --dev pytest pytest-django factory-boy

# Create the Django project
uv run django-admin startproject config .

# Run migrations and server
uv run python manage.py migrate
uv run python manage.py runserver

🔗 See also: Building Your First API with Django: A Beginner's Guide

Dockerfile with uv

uv is also excellent for Docker builds. It can dramatically speed up Docker layer caching:

FROM python:3.12-slim

# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

WORKDIR /app

# Copy dependency files first (for layer caching)
COPY pyproject.toml uv.lock ./

# Install dependencies (without project code)
RUN uv sync --frozen --no-install-project

# Copy project code
COPY . .

# Install the project itself
RUN uv sync --frozen

# Run with uv
CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

This approach maximizes Docker layer caching: if only your source code changes (not pyproject.toml or uv.lock), Docker reuses the cached dependency layer.

Conclusion: Should You Switch Today?

Yes. uv has matured rapidly and is production-ready. Here's a quick decision guide:

SituationRecommendation
New projectUse uv from day one
Existing pip projectMigrate gradually — start with uv pip as a drop-in
Existing Poetry projectMigrate when you have bandwidth — it's worth it
CI/CD pipelinesSwitch immediately — the speed gains are dramatic
Team projectMigrate together so everyone uses uv sync from the same uv.lock

uv's approach — a single, fast, opinionated tool — represents the right direction for Python package management. The ecosystem is moving this way, and the sooner you adopt it, the more you'll benefit from the growing ecosystem of uv-native tooling.

🔗 Related: Building a High-Performance Async API with FastAPI and PostgreSQL


📌 Up next: Redis Caching in Django and FastAPI: A Practical Guide

STAY IN TOUCH

Get notified when I publish something new, and unsubscribe at any time.