What is UV?

UV is an extremely fast Python package and project manager, written in Rust by Astral (the makers of Ruff). It is designed as an all-in-one replacement for a whole stack of tools that Python developers traditionally juggle separately: pip, pip-tools, pipx, virtualenv, poetry, and pyenv. Instead of installing and learning each of these individually, UV gives you one consistent CLI for installing Python itself, creating virtual environments, managing project dependencies, locking them for reproducibility, running scripts and tools, and publishing packages.

The headline benefit is speed — UV is commonly 10-100x faster than pip for installs because of its Rust implementation, a global cache that deduplicates package downloads across all your projects, and a highly parallelized resolver. Beyond speed, it also brings a more modern, declarative workflow (similar to what Poetry or npm/yarn offer) built around pyproject.toml and a lockfile (uv.lock), which makes builds reproducible across machines and CI.

This cheatsheet walks through installation, Python version management, project and dependency management, running code, scripts with inline dependencies, virtual environments, the pip-compatible interface, tool management (pipx-style), workspaces, configuration, environment variables, and common troubleshooting tips.

Installation

UV can be installed in several ways depending on your platform and existing toolchain.

# macOS / Linux — standalone installer script (recommended)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows — PowerShell installer
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

# Via pip, if you already have a Python environment
pip install uv

# Via pipx, to keep it isolated from any project environment
pipx install uv

# Via Homebrew (macOS/Linux)
brew install uv

# Via winget (Windows)
winget install --id=astral-sh.uv -e

# Via cargo, if you have a Rust toolchain
cargo install --locked uv

Once installed, keep UV itself up to date (only works if installed via the standalone installer):

uv self update       # upgrade uv to the latest release
uv --version          # check which version you have installed

Python Version Management

UV can download and manage standalone Python builds for you, so you don’t need pyenv or your OS package manager to get a specific Python version. This is especially handy for pinning a project to an exact Python release regardless of what’s installed system-wide.

uv python install 3.12          # download and install Python 3.12
uv python install 3.11 3.12 3.13  # install several versions at once
uv python install 3.12.4         # install an exact patch version

uv python list                   # list all installed and available-to-install versions
uv python list --only-installed  # list only versions already installed

uv python find 3.12              # print the path to a matching interpreter
uv python find                   # print the path to the default/active interpreter

uv python pin 3.12               # write a .python-version file pinning this project
uv python pin --global 3.12      # set a global default version for all projects

uv python uninstall 3.11         # remove an installed version

When you run uv venv, uv run, or uv sync in a project with a .python-version file (or a requires-python constraint in pyproject.toml), UV will automatically download the matching interpreter if it isn’t already installed — no separate step required.

Project Management

UV projects are organized around a pyproject.toml manifest (standard Python project metadata) and a uv.lock lockfile that records the exact resolved versions of every dependency, including transitive ones, so installs are perfectly reproducible across machines.

uv init                      # create a new project in the current directory
uv init my-project           # create a new project in ./my-project
uv init --lib                # create a library/package project (src/ layout, has a build system)
uv init --app                # create an application project (default, simple layout)
uv init --package            # alias for creating an installable package
uv init --no-readme          # skip generating a README.md

Adding and removing dependencies

uv add requests                       # add a runtime dependency, latest compatible version
uv add "requests>=2.31,<3"            # add with an explicit version constraint
uv add requests==2.31.0               # pin an exact version
uv add --dev pytest ruff              # add dependencies only needed for development
uv add --optional lint ruff           # add to a named optional/extra dependency group
uv add --group docs mkdocs            # add to a custom dependency group (PEP 735 style)
uv add git+https://github.com/org/repo  # add a dependency directly from a git repository
uv add ./local-package                # add a local path as an editable dependency

uv remove requests                    # remove a dependency from the project
uv remove --dev pytest                # remove a dev dependency

Syncing and locking

uv sync makes your .venv match the lockfile exactly (installing, upgrading, or removing packages as needed). uv lock recalculates the lockfile from your pyproject.toml without touching the environment.

uv sync                      # install/update the .venv to match uv.lock
uv sync --all-extras         # also install all optional extras
uv sync --extra lint         # install one specific extra
uv sync --group docs         # include a specific dependency group
uv sync --no-dev             # exclude dev dependencies (e.g. for production installs)
uv sync --locked             # fail instead of updating if the lockfile is stale
uv sync --frozen             # install exactly what's in the lockfile, skip any resolution step

uv lock                      # create or update uv.lock from pyproject.toml
uv lock --upgrade            # re-resolve and upgrade every dependency to latest allowed version
uv lock --upgrade-package requests  # upgrade just one package, leave the rest pinned
uv lock --check              # verify the lockfile is up to date without modifying it

uv tree                      # print the full resolved dependency tree
uv tree --package requests   # show where a specific package appears in the tree

Key project files to know:

FilePurpose
pyproject.tomlDeclares project metadata, dependencies, and build configuration
uv.lockExact, resolved, cross-platform dependency versions — commit this to version control
.venv/The project’s isolated virtual environment, auto-managed by UV
.python-versionPins which Python version the project should use

Running Code

uv run is the main entry point for executing anything inside your project’s environment. It automatically ensures the .venv exists and is in sync with uv.lock before running — so you never have to manually activate the environment or remember to run uv sync first.

uv run script.py                  # run a Python file inside the project's venv
uv run python                     # launch an interactive REPL inside the venv
uv run python -c "print('hi')"    # run an inline snippet
uv run pytest                     # run a tool/entry point that's a project dependency
uv run -- black . --check         # use -- to pass flags through to the underlying command
uv run --with httpx script.py     # run with an extra one-off dependency not in pyproject.toml
uv run --with "httpx>=0.27" script.py  # with a version constraint
uv run --no-sync script.py        # skip the automatic sync step (use the venv as-is)
uv run --python 3.11 script.py    # run using a specific Python version for this invocation

Scripts with Inline Dependencies (PEP 723)

For single-file scripts that need their own dependencies but don’t warrant a full project, UV supports PEP 723 inline script metadata — a small TOML block embedded directly at the top of the .py file.

uv init --script script.py          # scaffold a new script with inline metadata support
uv add --script script.py requests  # declare a dependency inline inside the script itself
uv remove --script script.py requests  # remove an inline dependency

uv run script.py                    # UV reads the inline metadata and builds an isolated,
                                     # cached environment on the fly just for this script

A script with inline metadata looks like this at the top of the file:

# /// script
# dependencies = [
#   "requests",
# ]
# ///

import requests
print(requests.get("https://example.com").status_code)

This makes scripts fully self-contained and shareable — anyone with UV installed can run the file with uv run script.py and get the exact right dependencies, with no manual setup.

Virtual Environments (manual/low-level control)

Most of the time uv run and uv sync manage the virtual environment for you automatically. But UV also exposes direct, low-level venv commands for cases where you want manual control (e.g. integrating with an IDE or another tool).

uv venv                        # create a .venv in the current directory
uv venv --python 3.12          # create it with a specific Python version
uv venv my-env                 # create the venv at a custom path/name
uv venv --seed                 # include pip/setuptools/wheel in the new venv

source .venv/bin/activate      # activate on macOS/Linux
.venv\Scripts\activate         # activate on Windows (cmd/PowerShell)
deactivate                     # leave the active virtual environment

Pip-Compatible Interface

For teams migrating gradually, or for workflows that still expect pip’s exact CLI, UV ships a drop-in uv pip subcommand that mirrors pip’s interface but runs with UV’s much faster resolver and installer.

uv pip install requests              # install a package
uv pip install -r requirements.txt   # install from a requirements file
uv pip install -e .                  # install the current project in editable mode
uv pip uninstall requests            # remove a package
uv pip list                          # list installed packages
uv pip freeze                        # print installed packages in requirements format
uv pip show requests                 # show metadata about an installed package
uv pip check                         # verify installed packages have compatible dependencies

uv pip compile requirements.in -o requirements.txt   # resolve and pin, like pip-compile
uv pip compile pyproject.toml -o requirements.txt    # compile from pyproject.toml
uv pip sync requirements.txt                          # make the environment match the file exactly

Note that uv pip operates on whatever environment is currently active (or .venv if present) and does not use the uv.lock project workflow — it’s meant as a faster substitute for raw pip commands, not the project-oriented workflow described above.

Tools (pipx replacement)

UV can install and run command-line tools published on PyPI in their own isolated environments, without polluting your project’s dependencies — equivalent to what pipx does.

uv tool install ruff           # install a CLI tool into an isolated, managed environment
uv tool install "ruff==0.5.0"  # install a specific version
uv tool run ruff check .       # run a tool without permanently installing it
uvx ruff check .               # shorthand alias for `uv tool run`
uvx black@24.0.0 .             # run a specific version ad hoc, without installing it
uvx --from ruff ruff-format .  # run a specific entry point from a package

uv tool list                   # list all installed tools
uv tool upgrade ruff           # upgrade one installed tool
uv tool upgrade --all          # upgrade every installed tool
uv tool uninstall ruff         # remove an installed tool
uv tool dir                    # show where tools are installed
uv tool update-shell           # ensure tool install directory is on PATH

Workspaces (multi-package projects)

For monorepos with multiple related packages, UV supports a workspace concept similar to Cargo workspaces, where a root pyproject.toml declares member packages that share a single lockfile and virtual environment.

# root pyproject.toml
[tool.uv.workspace]
members = ["packages/*"]
uv sync                           # syncs the whole workspace from one shared uv.lock
uv run --package my-subpackage script.py   # run in the context of a specific workspace member

Building & Publishing

uv build                     # build both sdist and wheel into dist/
uv build --wheel             # build only the wheel
uv build --sdist             # build only the source distribution

uv publish                   # upload built artifacts to PyPI (or a configured index)
uv publish --token <token>   # publish using an explicit API token
uv publish --publish-url <url>  # publish to a custom/private index

Configuration & Environment Variables

UV reads configuration from pyproject.toml (under [tool.uv]), a standalone uv.toml, or environment variables — useful for setting defaults like a private package index without repeating flags on every command.

# pyproject.toml
[tool.uv]
index-url = "https://pypi.org/simple"
Environment VariablePurpose
UV_INDEX_URLDefault package index to resolve/install from
UV_EXTRA_INDEX_URLAdditional package index(es) to search
UV_CACHE_DIROverride the location of UV’s global cache
UV_PYTHONForce a specific Python version/interpreter
UV_NO_SYNCDisable automatic syncing on uv run
UV_OFFLINEForce offline mode, using only cached packages
UV_SYSTEM_PYTHONAllow operations to use the system Python instead of a venv

Useful Flags Reference

FlagWhere it appliesPurpose
--frozensync, runUse the lockfile exactly as-is, skip re-resolution
--lockedsync, lockFail if the lockfile would need to change
--no-syncrunSkip auto-sync before running
--offlinemost commandsUse only cached packages, no network calls
--index-urlinstall-related commandsUse a custom package index for this invocation
--pythonmost commandsSpecify which Python version/interpreter to use
--all-extrassync, pip compileInclude every optional extra
--no-devsyncExclude development dependencies

Cache Management

UV keeps a global, content-addressed cache so identical package versions are never downloaded or built twice across all your projects on the machine.

uv cache dir            # show where the cache lives on disk
uv cache clean           # remove all cached data
uv cache clean requests  # remove cached data for a specific package
uv cache prune           # remove only unused/stale cache entries

Troubleshooting Tips

  • If uv run seems to be using the wrong Python version, check for a .python-version file and the requires-python field in pyproject.toml — these take precedence over your shell’s default interpreter.
  • If dependency resolution fails unexpectedly, run uv lock --upgrade to force a fresh resolution, or inspect uv tree to see what’s pulling in a conflicting version.
  • If you suspect a corrupted or stale cache, uv cache clean followed by uv sync will rebuild everything from scratch.
  • Use uv pip check to detect dependency conflicts in an existing environment without changing anything.
  • Add -v or -vv to most commands for verbose/debug output when diagnosing an issue.

Quick End-to-End Workflow Example

uv init my-app && cd my-app          # scaffold a new project
uv python pin 3.12                   # pin the Python version
uv add fastapi uvicorn                # add runtime dependencies
uv add --dev pytest ruff              # add dev dependencies
uv run uvicorn main:app --reload      # run the app inside the managed venv
uv run pytest                         # run the test suite
uv run ruff check .                   # lint the project
uv lock --upgrade                     # refresh the lockfile to latest compatible versions
git add pyproject.toml uv.lock        # commit the manifest and lockfile together

Created using Anthropic Claude. Verify commands against the latest uv documentation before relying on them, as CLI details may change between releases.