What it is

uv is a package and project manager for Python: the program you use to set up a Python project and keep it working. It ships as a single executable file with nothing else to install - not even Python, which it can download for you. The name is lowercase, always, including at the start of a sentence.

To see why it exists, look at what setting up a Python project used to take. You needed one tool to install the right version of Python, a second to create an isolated folder so this project's packages would not collide with another project's, a third to install the packages, a fourth to write down their exact versions so a colleague got the same ones, and a fifth to install command-line programs written in Python. Five tools, five sets of commands, five things to explain to whoever joins the project. Every one of them was reasonable on its own. Together they were the single most common reason a newcomer's first Python project did not run.

uv is all five, in one command with one consistent shape. That consolidation, not the speed, is the reason it spread.

Installing it takes one line and does not require Python to already be on the machine:

# macOS and Linux
$curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows, in PowerShell
$irm https://astral.sh/uv/install.ps1 | iex

If you already have Python and would rather not pipe a script into your shell, pip install uv and brew install uv both work. This article assumes you know roughly what Python is; if not, start with What is Python? and come back.

The tools it replaces

Astral's own description is "a single tool to replace pip, pip-tools, pipx, poetry, pyenv, twine, and virtualenv." That list only helps if you already know what those are, so here they are in plain terms, with what you type instead.

Old tool What it did uv command
pip Installed packages from the Python Package Index into whatever environment was active. uv add · uv pip install
virtualenv Created a per-project folder holding that project's own packages, so two projects could use different versions of the same library. uv venv, or nothing at all - uv makes one for you
pyenv Downloaded and switched between versions of Python itself, separately from whatever the operating system shipped. uv python install
pip-tools Turned a loose list of wanted packages into an exact, pinned list, so every machine installed identical versions. uv lock
pipx Installed Python command-line programs globally without letting their dependencies pollute your projects. uv tool install · uvx
poetry Managed a whole project - dependencies, lockfile, and packaging - as one thing, with its own file format. uv init · uv add · uv sync

Two of those deserve a note. uv's uv pip commands deliberately mirror pip's, so you can drop uv into an existing project and change nothing else - it is the low-risk way in. And poetry overlaps most, because it was solving the same consolidation problem; the practical difference is that uv also handles Python versions and tools, and stores project settings in the standard pyproject.toml rather than a format of its own.

A project, start to finish

The shortest complete example. Three commands take you from an empty folder to a running program with a dependency installed:

$uv init weather        # create the project folder and its files
$cd weather
$uv add requests        # install a package and record it as a dependency
$uv run main.py         # run the program with that package available

What each one did:

  • uv init created the folder with a pyproject.toml - the standard file describing a Python project - and a starter main.py.
  • uv add found a compatible version of requests, installed it, wrote it into pyproject.toml as a dependency, and recorded the exact version in a lockfile. It also created the isolated environment on the spot, in a hidden .venv folder, and excluded that folder from Git for you.
  • uv run ran the program inside that environment.

The last one is the habit worth forming. In the older workflow you had to "activate" an environment before working and remember whether you had - the source of an entire genre of confusing bug, where a package is definitely installed and Python definitely cannot see it. With uv run there is nothing to activate and nothing to forget: it checks the environment is current, fixes it if not, then runs your command. Anyone else who clones the project types uv run and gets the same setup, without being told the steps.

The lockfile

A lockfile is a file that records the exact version of every package your project ended up with, including the packages your packages depend on. Without one, "install the dependencies" means "install whatever is newest today", and a project that worked in March breaks in April on a machine that was set up in between. With one, everybody installs the same thing.

uv writes uv.lock next to your pyproject.toml and keeps it current automatically. Two rules: commit it to version control, and never edit it by hand.

The useful property is that uv.lock is universal - it captures what would be installed on every operating system, processor, and Python version, not just the one that happened to create it. That is why the same lockfile works for a colleague on Windows, a Mac laptop, and a Linux build server. Older tooling produced a per-machine list and quietly fell apart across platforms.

One catch to know about, because it will come up if you work with other tools: uv.lock is uv's own format and nothing else reads it. Python does now have a standardised lockfile format of its own, pylock.toml, defined in PEP 751, and uv can export to it with uv export -o pylock.toml. But uv keeps its own format as the primary one, because the standard cannot yet express everything uv needs.

Python versions and one-off tools

Two jobs that used to need their own tools each collapse into a subcommand.

Python itself. uv python install 3.13 downloads that version and puts it under uv's control, leaving whatever Python your operating system ships alone - which you should never uninstall or upgrade by hand, because parts of the system depend on it. A project can pin its version in a .python-version file, and uv will fetch that version automatically if the machine does not have it. Anyone arriving at the project gets the right interpreter without being told which one it is.

Command-line programs. Plenty of useful tools are distributed as Python packages, and installing them into your project's environment is a mistake - your project does not depend on them, and their dependencies can conflict with yours. uv tool install ruff puts one on your PATH in its own isolated environment. uvx ruff check goes further and runs it without installing anything at all, in a throwaway environment it discards afterwards. For a tool you use twice a year, uvx is the entire workflow.

Why it is fast

Astral's own benchmarks claim 10 to 100 times faster than pip, which is the number everyone quotes. Treat vendor benchmarks as vendor benchmarks, but the gap is real and large enough that you notice it in ordinary work: installs that took most of a minute finish before you look away.

Three plain reasons, no internals required. It is compiled Rust rather than Python, so the program itself starts and runs quickly. It keeps one download cache shared across all your projects, so the second project that needs a package does not re-download it. And it does the slow part - working out which combination of versions satisfies everything - with an algorithm built for the job rather than one bolted on later.

Where this actually pays is continuous integration, where a fresh machine installs everything from scratch on every single commit, several times a day. That is the bill most teams notice.

Still: speed is a nice-to-have. If uv were merely as fast as pip and still replaced five tools with one, the argument for using it would be about the same.

What it costs you

Four things to know before you standardise a team on it.

  • It is not finished. uv is still on 0.x version numbers, with releases landing most weeks. That is a healthy pace, not a warning sign, but pin the version in CI rather than always taking the newest, and read release notes before upgrading.
  • The lockfile is uv's. Adopting uv means your project's pinned versions live in a format only uv reads, as covered in Section 04. The pylock.toml export is the escape hatch, and it is a real one, but it is an export rather than the thing itself.
  • It is not a conda replacement. If your work depends on conda's channels for scientific packages that are not published as ordinary Python packages, uv does not cover that.
  • Ownership changed. In March 2026 OpenAI announced it would acquire Astral, and the team behind uv joined OpenAI's Codex group. OpenAI stated it plans to continue supporting Astral's open source products. uv remains open source under the MIT and Apache-2.0 licences, so nothing about today's tool changed - but a tool this central to your workflow now has a very large owner with its own priorities, and that is worth knowing rather than discovering later.

None of that argues against adopting it. The honest summary is that uv is the best answer the Python ecosystem has had to a problem it lived with for fifteen years, and the risks are the ordinary risks of depending on someone else's tool. If you are starting a Python project this week, start it with uv.