Getting Started with uv - The Modern Python Package Manager

Python dependency management has historically been fragmented across multiple tools: pip, pip-tools, pipx, poetry, pyenv, and more. Enter uv - an extremely fast Python package and project manager written in Rust by Astral, the creators of Ruff. It’s designed to be a single tool that replaces the entire Python toolchain.

Why uv?

  • Blazingly fast: 10-100x faster than pip due to its Rust implementation
  • All-in-one: Replaces pip, pip-tools, pipx, poetry, pyenv, and virtualenv
  • Python version management: Install and manage multiple Python versions
  • Modern project management: Uses standard pyproject.toml for configuration
  • Reproducible builds: Built-in lockfile support for deterministic installations
  • Cross-platform: Works on macOS, Linux, and Windows

Installing uv

On macOS and Linux

The recommended way to install uv is using the standalone installer:

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

On macOS with Homebrew

brew install uv

On Windows

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

Verify Installation

uv --version

Managing Python Versions

One of uv’s most powerful features is its ability to manage Python installations directly - no need for pyenv or similar tools.

Install Python

# Install the latest Python version
uv python install

# Install a specific version
uv python install 3.12

# Install multiple versions at once
uv python install 3.10 3.11 3.12

# Install a specific patch version
uv python install cpython@3.11.5

# Install PyPy
uv python install pypy@3.9

List Installed Versions

# List all available Python versions
uv python list

# List only installed versions
uv python list --only-installed

Pin Python Version for a Project

# Pin a version for the current project
uv python pin 3.12

# This creates a .python-version file

Find Python Interpreters

# Find any Python
uv python find

# Find a specific version
uv python find 3.11

Creating and Managing Projects

Initialize a New Project

# Create a new project in a new directory
uv init my-project
cd my-project

# Or initialize in the current directory
mkdir my-project && cd my-project
uv init

This creates a basic project structure:

my-project/
├── .python-version
├── README.md
├── hello.py
└── pyproject.toml

Project Configuration (pyproject.toml)

The pyproject.toml is the heart of your project configuration:

[project]
name = "my-project"
version = "0.1.0"
description = "My awesome project"
requires-python = ">=3.12"
dependencies = [
"fastapi",
"pydantic>2",
]

[dependency-groups]
dev = [
"pytest",
"ruff",
"mypy",
]

Adding Dependencies

# Add a production dependency
uv add requests

# Add a specific version
uv add "django>=4.0"

# Add a development dependency
uv add --dev pytest

# Add multiple packages
uv add flask sqlalchemy redis

Removing Dependencies

uv remove requests

Syncing Dependencies

# Install all dependencies from pyproject.toml and uv.lock
uv sync

# Include development dependencies
uv sync --dev

# Install with all extras
uv sync --all-extras

Working with Virtual Environments

Creating Virtual Environments

# Create a virtual environment with the default Python
uv venv

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

# Create in a custom location
uv venv /path/to/venv

Activating the Virtual Environment

# On macOS/Linux
source .venv/bin/activate

# On Windows
.venv\Scripts\activate

However, with uv run, you often don’t need to manually activate environments!

Running Commands with uv run

The uv run command is incredibly powerful - it automatically creates/syncs the virtual environment and runs commands within it:

# Run a Python script
uv run python main.py

# Run a script with a specific Python version
uv run --python 3.11 python main.py

# Run a module
uv run -m pytest

# Run an installed CLI tool
uv run ruff check .

Locking Dependencies

uv automatically creates and maintains a uv.lock file for reproducible builds:

# Create or update the lockfile
uv lock

# Update a specific package
uv lock --upgrade-package requests

# Update all packages
uv lock --upgrade

Migrating from pip/requirements.txt

Using requirements.txt with uv

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

# Compile requirements (like pip-tools)
uv pip compile requirements.in -o requirements.txt

# Compile from pyproject.toml
uv pip compile pyproject.toml -o requirements.txt

Converting requirements.txt to pyproject.toml

If you have an existing requirements.txt, you can migrate to a modern project structure:

  1. Initialize a new project:
uv init
  1. Add your existing dependencies:
uv add $(cat requirements.txt | grep -v "^#" | tr '\n' ' ')

Running One-off Scripts and Tools

Run Tools Without Installing

# Run a tool without permanently installing it
uv tool run ruff check .

# Or use the shorthand 'uvx'
uvx black .
uvx isort .

Install Global Tools

# Install a tool globally (like pipx)
uv tool install ruff
uv tool install black
uv tool install httpie

CI/CD Integration

GitHub Actions Example

name: CI

on: [push, pull_request]

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

- name: Install uv
uses: astral-sh/setup-uv@v4

- name: Install dependencies
run: uv sync --locked --all-extras --dev

- name: Run tests
run: uv run pytest tests

- name: Run linting
run: uv run ruff check .

Best Practices

1. Always Use a Lockfile

Commit uv.lock to version control for reproducible builds:

uv lock
git add uv.lock
git commit -m "Add lockfile"

2. Separate Dev Dependencies

Use dependency groups to separate production and development dependencies:

[project]
dependencies = [
"fastapi",
"uvicorn",
]

[dependency-groups]
dev = ["pytest", "ruff", "mypy"]
test = ["pytest", "pytest-cov"]

3. Pin Python Version

Create a .python-version file to ensure consistency:

uv python pin 3.12

4. Use uv run Instead of Activating

Let uv run handle the virtual environment automatically:

# Instead of:
source .venv/bin/activate && python main.py

# Use:
uv run python main.py

5. Leverage uv.lock for CI

Use --locked in CI to ensure exact reproducibility:

uv sync --locked

Quick Reference

Task Command
Install uv curl -LsSf https://astral.sh/uv/install.sh | sh
Install Python uv python install 3.12
Create project uv init my-project
Add dependency uv add package-name
Add dev dependency uv add --dev package-name
Remove dependency uv remove package-name
Sync dependencies uv sync
Run script uv run python script.py
Run tool uvx tool-name
Create venv uv venv
Lock dependencies uv lock

Conclusion

uv represents a significant step forward in Python tooling. Its speed, unified approach, and modern features make it an excellent choice for both new projects and migrating existing ones. By adopting uv, you can simplify your Python development workflow while enjoying blazingly fast dependency resolution and installation.

For more information, check out the official uv documentation.


   Reprint policy


《Getting Started with uv - The Modern Python Package Manager》 by Isaac Zhou is licensed under a Creative Commons Attribution 4.0 International License
  TOC