How to Add a Dependency to a uv Project
uv manages project dependencies through one command. uv add writes the package into your pyproject.toml, resolves a compatible version into the lockfile, and installs it into the project’s virtual environment. pip splits those three steps across pip install and a hand edit of your project metadata.
These commands assume a uv project, meaning a directory with a pyproject.toml. Run uv init first to create one if you don’t have it yet.
Add a package
Name the package and uv does the rest:
$ uv add httpx
Using CPython 3.12.10 interpreter at: /usr/local/bin/python3.12
Creating virtual environment at: .venv
Resolved 8 packages in 114ms
Prepared 7 packages in 51ms
Installed 7 packages in 18ms
+ anyio==4.14.2
+ certifi==2026.7.22
+ h11==0.16.0
+ httpcore==1.0.9
+ httpx==0.28.1
+ idna==3.18
+ typing-extensions==4.16.0
Three files change. pyproject.toml gains a line in its dependencies array ("httpx>=0.28.1"), uv.lock records the exact resolved version and its hashes, and the .venv directory receives the install. The first uv add in a fresh project also creates that .venv, which is why the Creating virtual environment line appears before anything installs. Anyone who clones the project and runs uv sync reproduces the same set of versions.
Add several at once by listing them:
uv add httpx richPin a version
Pass a version specifier in quotes so the shell doesn’t read > as a redirect:
uv add 'httpx>=0.27,<1.0'uv writes that range to pyproject.toml and installs the newest version inside it. Without a specifier, uv adds a lower bound at the version it resolved (httpx>=0.28.1), which lets future upgrades move forward freely. To later raise a version ceiling that is blocking an upgrade, see how to upgrade a dependency past its version ceiling.
Add a development dependency
Tools you use while working on the project, but that its users don’t need, belong in a dependency group. Pass --dev to put a package in the dev group:
uv add --dev pytestThis writes to [dependency-groups] in pyproject.toml rather than the main dependencies array. The dev group installs when you run uv sync locally but is left out when someone installs your package as a dependency of theirs. Use --group <name> to target a named group other than dev.
Add an optional dependency
An optional dependency ships as an extra that users opt into (pip install yourpackage[plot]). Add one with --optional and the extra’s name:
uv add --optional plot matplotlibuv writes matplotlib under a plot key in [project.optional-dependencies]. Unlike a dev dependency, an extra is published with your package, so downstream users can request it.
Add from Git, a URL, or a local path
uv resolves sources beyond the default package index. Point at a Git repository with the package @ git+URL form:
uv add "httpx @ git+https://github.com/encode/httpx"Pin the reference with --tag, --branch, or --rev to avoid tracking a moving branch:
uv add "httpx @ git+https://github.com/encode/httpx" --tag 0.28.1uv records the repository under a [tool.uv.sources] table in pyproject.toml and keeps the package name in your dependencies list, so the source and the requirement stay separate.
For a package you develop alongside this project, add it from a local path as an editable install so your edits take effect without reinstalling:
uv add --editable ../my-libraryRemove a dependency
uv remove reverses uv add, updating the same three places:
uv remove httpxIt drops the package from pyproject.toml, re-resolves and rewrites uv.lock, and uninstalls it from the virtual environment along with any dependencies no longer needed.
Learn More
- Managing dependencies: the uv reference for every
addflag and source type. - uv Reference: the full command surface and configuration options.
- What is a lockfile? explains what uv.lock records and why it matters.
- How to pin dependencies with hashes in uv covers verifying downloads against recorded hashes.
- How to translate pip commands to uv maps
pip installand friends to their uv equivalents.