Python Dependency Management: Is `uv` the Winner?

python dev tooling

Python dependency management has been a mess for years. pip, pip-tools, pipenv, poetry, conda—each with trade-offs. Then Astral released uv, and suddenly everything feels fast.

The State of Python Packaging (Before uv)

ToolPurposePain Points
pipInstall packagesNo lockfile, slow resolver
pip-toolsLock dependenciesSeparate tool, still slow
pipenvAll-in-oneSlow, complex, abandoned feel
poetryModern packagingSlow resolution, some compatibility issues
condaScientific computingSeparate ecosystem, mixing issues

Common refrain: “Why is this so slow?”

Enter uv

Astral (the Ruff creators) built uv—a pip replacement written in Rust:

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

# Or with pip (ironic but works)
pip install uv

Speed Comparison

uv is fast. Really fast.

OperationpipuvSpeedup
Install Django4.5s0.3s15x
Lock 100 deps45s1.2s37x
Create venv2.1s0.05s42x
Resolve conflicts30s0.8s37x

The secret: Rust, parallel downloads, smart caching, and a complete rewrite of the resolver.

Basic Usage

Package Installation

# Drop-in pip replacement
uv pip install django
uv pip install -r requirements.txt

# Or use the simpler syntax
uv add django  # Adds to pyproject.toml and installs
uv remove django  # Removes cleanly

Virtual Environments

# Create
uv venv

# Create with specific Python
uv venv --python 3.12

# Activate (same as before)
source .venv/bin/activate

Project Management

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

# Add dependencies
uv add django
uv add pytest --dev  # Development dependency

# Lock dependencies
uv lock

# Sync environment with lockfile
uv sync

pyproject.toml Native

uv uses pyproject.toml as the source of truth:

[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = [
    "django>=5.0",
    "djangorestframework>=3.14",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "ruff>=0.1",
]

[tool.uv]
dev-dependencies = [
    "pytest>=8.0",
]

Lockfiles

uv generates uv.lock for reproducible installs:

# Generate lockfile
uv lock

# Install exactly what's in lockfile
uv sync

The lockfile is cross-platform by default—it works on Linux, macOS, and Windows.

Python Version Management

uv can manage Python itself:

# List available versions
uv python list

# Install a specific version
uv python install 3.12

# Pin version for project
uv python pin 3.12

No more pyenv? Possibly.

Migration from pip/poetry

From pip + requirements.txt

# Initialize uv in existing project
uv init --no-workspace

# Import requirements
uv add -r requirements.txt

# Generate lockfile
uv lock

From poetry

# Convert poetry to uv
uv init

# Poetry dependencies transfer via pyproject.toml
# uv reads the same [project.dependencies]
uv lock
uv sync

CI/CD Integration

GitHub Actions

- name: Install uv
  uses: astral-sh/setup-uv@v2
  
- name: Install dependencies
  run: uv sync

- name: Run tests
  run: uv run pytest

Docker

FROM python:3.12-slim

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

# Copy and install
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev

COPY . .
CMD ["uv", "run", "python", "main.py"]

The uv run Command

Run without activating venv:

# Run script
uv run python script.py

# Run with inline dependencies
uv run --with requests python -c "import requests; print(requests.__version__)"

# Run pytest
uv run pytest

Trade-offs

What uv Does Well

Current Limitations

Should You Switch?

Switch now if:

Wait if:

The Ecosystem Unification

uv is part of Astral’s vision:

One company addressing Python’s tooling fragmentation with Rust-powered tools.

Final Thoughts

uv feels like the future. It’s fast, well-designed, and actively developed.

Try it on a new project. Feel the speed. Then decide if it’s time to migrate your existing projects.

Python packaging might finally be solved.


Speed is the killer feature nobody knew they needed.

All posts