uv/docs/concepts/projects/dependencies.md
Zanie Blue ec18f4813a
Some checks failed
CI / Determine changes (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / cargo shear (push) Has been cancelled
CI / typos (push) Has been cancelled
CI / mkdocs (push) Has been cancelled
CI / cargo test | macos (push) Has been cancelled
CI / cargo test | windows (push) Has been cancelled
CI / check windows trampoline | aarch64 (push) Has been cancelled
CI / check system | alpine (push) Has been cancelled
CI / check windows trampoline | i686 (push) Has been cancelled
CI / cargo clippy | ubuntu (push) Has been cancelled
CI / cargo clippy | windows (push) Has been cancelled
CI / cargo dev generate-all (push) Has been cancelled
CI / cargo test | ubuntu (push) Has been cancelled
CI / integration test | pypy on windows (push) Has been cancelled
CI / integration test | pyodide on ubuntu (push) Has been cancelled
CI / check system | python on ubuntu (push) Has been cancelled
CI / integration test | github actions (push) Has been cancelled
CI / integration test | uv publish (push) Has been cancelled
CI / check windows trampoline | x86_64 (push) Has been cancelled
CI / test windows trampoline | i686 (push) Has been cancelled
CI / test windows trampoline | x86_64 (push) Has been cancelled
CI / build binary | linux libc (push) Has been cancelled
CI / build binary | linux musl (push) Has been cancelled
CI / build binary | macos aarch64 (push) Has been cancelled
CI / build binary | macos x86_64 (push) Has been cancelled
CI / build binary | windows x86_64 (push) Has been cancelled
CI / build binary | windows aarch64 (push) Has been cancelled
CI / cargo build (msrv) (push) Has been cancelled
CI / build binary | freebsd (push) Has been cancelled
CI / smoke test | macos (push) Has been cancelled
CI / ecosystem test | pydantic/pydantic-core (push) Has been cancelled
CI / ecosystem test | prefecthq/prefect (push) Has been cancelled
CI / ecosystem test | pallets/flask (push) Has been cancelled
CI / smoke test | linux (push) Has been cancelled
CI / smoke test | windows x86_64 (push) Has been cancelled
CI / smoke test | windows aarch64 (push) Has been cancelled
CI / integration test | conda on ubuntu (push) Has been cancelled
CI / integration test | deadsnakes python3.9 on ubuntu (push) Has been cancelled
CI / integration test | free-threaded on windows (push) Has been cancelled
CI / integration test | pypy on ubuntu (push) Has been cancelled
CI / integration test | graalpy on ubuntu (push) Has been cancelled
CI / integration test | graalpy on windows (push) Has been cancelled
CI / integration test | free-threaded python on github actions (push) Has been cancelled
CI / integration test | determine publish changes (push) Has been cancelled
CI / integration test | registries (push) Has been cancelled
CI / integration test | uv_build (push) Has been cancelled
CI / check cache | ubuntu (push) Has been cancelled
CI / check cache | macos aarch64 (push) Has been cancelled
CI / check system | python on debian (push) Has been cancelled
CI / check system | python on fedora (push) Has been cancelled
CI / check system | python on rocky linux 8 (push) Has been cancelled
CI / check system | python on rocky linux 9 (push) Has been cancelled
CI / check system | graalpy on ubuntu (push) Has been cancelled
CI / check system | python3.10 on windows x86-64 (push) Has been cancelled
CI / check system | python3.10 on windows x86 (push) Has been cancelled
CI / check system | pypy on ubuntu (push) Has been cancelled
CI / check system | pyston (push) Has been cancelled
CI / check system | python on macos aarch64 (push) Has been cancelled
CI / check system | homebrew python on macos aarch64 (push) Has been cancelled
CI / check system | python on macos x86-64 (push) Has been cancelled
CI / check system | x86-64 python3.13 on windows aarch64 (push) Has been cancelled
CI / check system | conda3.11 on macos aarch64 (push) Has been cancelled
CI / check system | conda3.8 on macos aarch64 (push) Has been cancelled
CI / check system | conda3.11 on linux x86-64 (push) Has been cancelled
CI / check system | conda3.8 on linux x86-64 (push) Has been cancelled
CI / check system | conda3.11 on windows x86-64 (push) Has been cancelled
CI / check system | conda3.8 on windows x86-64 (push) Has been cancelled
CI / check system | python3.13 on windows x86-64 (push) Has been cancelled
CI / check system | windows registry (push) Has been cancelled
CI / check system | python3.12 via chocolatey (push) Has been cancelled
CI / check system | python3.9 via pyenv (push) Has been cancelled
CI / check system | python3.13 (push) Has been cancelled
CI / check system | amazonlinux (push) Has been cancelled
CI / check system | embedded python3.10 on windows x86-64 (push) Has been cancelled
CI / benchmarks | walltime aarch64 linux (push) Has been cancelled
CI / benchmarks | instrumented (push) Has been cancelled
Fix typo (#14341)
2025-06-28 11:32:03 -05:00

24 KiB
Raw Blame History

Managing dependencies

Dependency fields

Dependencies of the project are defined in several fields:

!!! note

The `project.dependencies` and `project.optional-dependencies` fields can be used even if
project isn't going to be published. `dependency-groups` are a recently standardized feature
and may not be supported by all tools yet.

uv supports modifying the project's dependencies with uv add and uv remove, but dependency metadata can also be updated by editing the pyproject.toml directly.

Adding dependencies

To add a dependency:

$ uv add httpx

An entry will be added in the project.dependencies field:

[project]
name = "example"
version = "0.1.0"
dependencies = ["httpx>=0.27.2"]

The --dev, --group, or --optional flags can be used to add dependencies to an alternative field.

The dependency will include a constraint, e.g., >=0.27.2, for the most recent, compatible version of the package. The kind of bound can be adjusted with --bounds, or the constraint can be provided directly:

$ uv add "httpx>=0.20"

When adding a dependency from a source other than a package registry, uv will add an entry in the sources field. For example, when adding httpx from GitHub:

$ uv add "httpx @ git+https://github.com/encode/httpx"

The pyproject.toml will include a Git source entry:

[project]
name = "example"
version = "0.1.0"
dependencies = [
    "httpx",
]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx" }

If a dependency cannot be used, uv will display an error.:

$ uv add "httpx>9999"
  × No solution found when resolving dependencies:
  ╰─▶ Because only httpx<=1.0.0b0 is available and your project depends on httpx>9999,
      we can conclude that your project's requirements are unsatisfiable.

Importing dependencies

Dependencies declared in a requirements.txt file can be added to the project with the -r option:

uv add -r requirements.txt

Removing dependencies

To remove a dependency:

$ uv remove httpx

The --dev, --group, or --optional flags can be used to remove a dependency from a specific table.

If a source is defined for the removed dependency, and there are no other references to the dependency, it will also be removed.

Changing dependencies

To change an existing dependency, e.g., to use a different constraint for httpx:

$ uv add "httpx>0.1.0"

!!! note

In this example, we are changing the constraints for the dependency in the `pyproject.toml`.
The locked version of the dependency will only change if necessary to satisfy the new
constraints. To force the package version to update to the latest within the constraints, use `--upgrade-package <name>`, e.g.:

```console
$ uv add "httpx>0.1.0" --upgrade-package httpx
```

See the [lockfile](./sync.md#upgrading-locked-package-versions) documentation for more details
on upgrading packages.

Requesting a different dependency source will update the tool.uv.sources table, e.g., to use httpx from a local path during development:

$ uv add "httpx @ ../httpx"

Platform-specific dependencies

To ensure that a dependency is only installed on a specific platform or on specific Python versions, use environment markers.

For example, to install jax on Linux, but not on Windows or macOS:

$ uv add "jax; sys_platform == 'linux'"

The resulting pyproject.toml will then include the environment marker in the dependency definition:

[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["jax; sys_platform == 'linux'"]

Similarly, to include numpy on Python 3.11 and later:

$ uv add "numpy; python_version >= '3.11'"

See Python's environment marker documentation for a complete enumeration of the available markers and operators.

!!! tip

Dependency sources can also be [changed per-platform](#platform-specific-sources).

Project dependencies

The project.dependencies table represents the dependencies that are used when uploading to PyPI or building a wheel. Individual dependencies are specified using dependency specifiers syntax, and the table follows the PEP 621 standard.

project.dependencies defines the list of packages that are required for the project, along with the version constraints that should be used when installing them. Each entry includes a dependency name and version. An entry may include extras or environment markers for platform-specific packages. For example:

[project]
name = "albatross"
version = "0.1.0"
dependencies = [
  # Any version in this range
  "tqdm >=4.66.2,<5",
  # Exactly this version of torch
  "torch ==2.2.2",
  # Install transformers with the torch extra
  "transformers[torch] >=4.39.3,<5",
  # Only install this package on older python versions
  # See "Environment Markers" for more information
  "importlib_metadata >=7.1.0,<8; python_version < '3.10'",
  "mollymawk ==0.1.0"
]

Dependency sources

The tool.uv.sources table extends the standard dependency tables with alternative dependency sources, which are used during development.

Dependency sources add support for common patterns that are not supported by the project.dependencies standard, like editable installations and relative paths. For example, to install foo from a directory relative to the project root:

[project]
name = "example"
version = "0.1.0"
dependencies = ["foo"]

[tool.uv.sources]
foo = { path = "./packages/foo" }

The following dependency sources are supported by uv:

  • Index: A package resolved from a specific package index.
  • Git: A Git repository.
  • URL: A remote wheel or source distribution.
  • Path: A local wheel, source distribution, or project directory.
  • Workspace: A member of the current workspace.

!!! important

Sources are only respected by uv. If another tool is used, only the definitions in the standard
project tables will be used. If another tool is being used for development, any metadata
provided in the source table will need to be re-specified in the other tool's format.

Index

To add Python package from a specific index, use the --index option:

$ uv add torch --index pytorch=https://download.pytorch.org/whl/cpu

uv will store the index in [[tool.uv.index]] and add a [tool.uv.sources] entry:

[project]
dependencies = ["torch"]

[tool.uv.sources]
torch = { index = "pytorch" }

[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"

!!! tip

The above example will only work on x86-64 Linux, due to the specifics of the PyTorch index.
See the [PyTorch guide](../../guides/integration/pytorch.md) for more information about setting
up PyTorch.

Using an index source pins a package to the given index — it will not be downloaded from other indexes.

When defining an index, an explicit flag can be included to indicate that the index should only be used for packages that explicitly specify it in tool.uv.sources. If explicit is not set, other packages may be resolved from the index, if not found elsewhere.

[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
explicit = true

Git

To add a Git dependency source, prefix a Git-compatible URL with git+.

For example:

$ # Install over HTTP(S).
$ uv add git+https://github.com/encode/httpx

$ # Install over SSH.
$ uv add git+ssh://git@github.com/encode/httpx
[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx" }

Specific Git references can be requested, e.g., a tag:

$ uv add git+https://github.com/encode/httpx --tag 0.27.0
[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx", tag = "0.27.0" }

Or, a branch:

$ uv add git+https://github.com/encode/httpx --branch main
[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx", branch = "main" }

Or, a revision (commit):

$ uv add git+https://github.com/encode/httpx --rev 326b9431c761e1ef1e00b9f760d1f654c8db48c6
[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx", rev = "326b9431c761e1ef1e00b9f760d1f654c8db48c6" }

A subdirectory may be specified if the package isn't in the repository root:

$ uv add git+https://github.com/langchain-ai/langchain#subdirectory=libs/langchain
[project]
dependencies = ["langchain"]

[tool.uv.sources]
langchain = { git = "https://github.com/langchain-ai/langchain", subdirectory = "libs/langchain" }

URL

To add a URL source, provide a https:// URL to either a wheel (ending in .whl) or a source distribution (typically ending in .tar.gz or .zip; see here for all supported formats).

For example:

$ uv add "https://files.pythonhosted.org/packages/5c/2d/3da5bdf4408b8b2800061c339f240c1802f2e82d55e50bd39c5a881f47f0/httpx-0.27.0.tar.gz"

Will result in a pyproject.toml with:

[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { url = "https://files.pythonhosted.org/packages/5c/2d/3da5bdf4408b8b2800061c339f240c1802f2e82d55e50bd39c5a881f47f0/httpx-0.27.0.tar.gz" }

URL dependencies can also be manually added or edited in the pyproject.toml with the { url = <url> } syntax. A subdirectory may be specified if the source distribution isn't in the archive root.

Path

To add a path source, provide the path of a wheel (ending in .whl), a source distribution (typically ending in .tar.gz or .zip; see here for all supported formats), or a directory containing a pyproject.toml.

For example:

$ uv add /example/foo-0.1.0-py3-none-any.whl

Will result in a pyproject.toml with:

[project]
dependencies = ["foo"]

[tool.uv.sources]
foo = { path = "/example/foo-0.1.0-py3-none-any.whl" }

The path may also be a relative path:

$ uv add ./foo-0.1.0-py3-none-any.whl

Or, a path to a project directory:

$ uv add ~/projects/bar/

!!! important

An [editable installation](#editable-dependencies) is not used for path dependencies by
default. An editable installation may be requested for project directories:

```console
$ uv add --editable ../projects/bar/
```

Which will result in a `pyproject.toml` with:

```toml title="pyproject.toml"
[project]
dependencies = ["bar"]

[tool.uv.sources]
bar = { path = "../projects/bar", editable = true }
```

Similarly, if a project is marked as a [non-package](./config.md#build-systems), but you'd
like to install it in the environment as a package, set `package = true` on the source:

```toml title="pyproject.toml"
[project]
dependencies = ["bar"]

[tool.uv.sources]
bar = { path = "../projects/bar", package = true }
```

For multiple packages in the same repository, [_workspaces_](./workspaces.md) may be a better
fit.

Workspace member

To declare a dependency on a workspace member, add the member name with { workspace = true }. All workspace members must be explicitly stated. Workspace members are always editable . See the workspace documentation for more details on workspaces.

[project]
dependencies = ["foo==0.1.0"]

[tool.uv.sources]
foo = { workspace = true }

[tool.uv.workspace]
members = [
  "packages/foo"
]

Platform-specific sources

You can limit a source to a given platform or Python version by providing dependency specifiers-compatible environment markers for the source.

For example, to pull httpx from GitHub, but only on macOS, use the following:

[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx", tag = "0.27.2", marker = "sys_platform == 'darwin'" }

By specifying the marker on the source, uv will still include httpx on all platforms, but will download the source from GitHub on macOS, and fall back to PyPI on all other platforms.

Multiple sources

You can specify multiple sources for a single dependency by providing a list of sources, disambiguated by PEP 508-compatible environment markers.

For example, to pull in different httpx tags on macOS vs. Linux:

[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = [
  { git = "https://github.com/encode/httpx", tag = "0.27.2", marker = "sys_platform == 'darwin'" },
  { git = "https://github.com/encode/httpx", tag = "0.24.1", marker = "sys_platform == 'linux'" },
]

This strategy extends to using different indexes based on environment markers. For example, to install torch from different PyTorch indexes based on the platform:

[project]
dependencies = ["torch"]

[tool.uv.sources]
torch = [
  { index = "torch-cpu", marker = "platform_system == 'Darwin'"},
  { index = "torch-gpu", marker = "platform_system == 'Linux'"},
]

[[tool.uv.index]]
name = "torch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true

[[tool.uv.index]]
name = "torch-gpu"
url = "https://download.pytorch.org/whl/cu124"
explicit = true

Disabling sources

To instruct uv to ignore the tool.uv.sources table (e.g., to simulate resolving with the package's published metadata), use the --no-sources flag:

$ uv lock --no-sources

The use of --no-sources will also prevent uv from discovering any workspace members that could satisfy a given dependency.

Optional dependencies

It is common for projects that are published as libraries to make some features optional to reduce the default dependency tree. For example, Pandas has an excel extra and a plot extra to avoid installation of Excel parsers and matplotlib unless someone explicitly requires them. Extras are requested with the package[<extra>] syntax, e.g., pandas[plot, excel].

Optional dependencies are specified in [project.optional-dependencies], a TOML table that maps from extra name to its dependencies, following dependency specifiers syntax.

Optional dependencies can have entries in tool.uv.sources the same as normal dependencies.

[project]
name = "pandas"
version = "1.0.0"

[project.optional-dependencies]
plot = [
  "matplotlib>=3.6.3"
]
excel = [
  "odfpy>=1.4.1",
  "openpyxl>=3.1.0",
  "python-calamine>=0.1.7",
  "pyxlsb>=1.0.10",
  "xlrd>=2.0.1",
  "xlsxwriter>=3.0.5"
]

To add an optional dependency, use the --optional <extra> option:

$ uv add httpx --optional network

!!! note

If you have optional dependencies that conflict with one another, resolution will fail
unless you explicitly [declare them as conflicting](./config.md#conflicting-dependencies).

Sources can also be declared as applying only to a specific optional dependency. For example, to pull torch from different PyTorch indexes based on an optional cpu or gpu extra:

[project]
dependencies = []

[project.optional-dependencies]
cpu = [
  "torch",
]
gpu = [
  "torch",
]

[tool.uv.sources]
torch = [
  { index = "torch-cpu", extra = "cpu" },
  { index = "torch-gpu", extra = "gpu" },
]

[[tool.uv.index]]
name = "torch-cpu"
url = "https://download.pytorch.org/whl/cpu"

[[tool.uv.index]]
name = "torch-gpu"
url = "https://download.pytorch.org/whl/cu124"

Development dependencies

Unlike optional dependencies, development dependencies are local-only and will not be included in the project requirements when published to PyPI or other indexes. As such, development dependencies are not included in the [project] table.

Development dependencies can have entries in tool.uv.sources the same as normal dependencies.

To add a development dependency, use the --dev flag:

$ uv add --dev pytest

uv uses the [dependency-groups] table (as defined in PEP 735) for declaration of development dependencies. The above command will create a dev group:

[dependency-groups]
dev = [
  "pytest >=8.1.1,<9"
]

The dev group is special-cased; there are --dev, --only-dev, and --no-dev flags to toggle inclusion or exclusion of its dependencies. See --no-default-groups to disable all default groups instead. Additionally, the dev group is synced by default.

Dependency groups

Development dependencies can be divided into multiple groups, using the --group flag.

For example, to add a development dependency in the lint group:

$ uv add --group lint ruff

Which results in the following [dependency-groups] definition:

[dependency-groups]
dev = [
  "pytest"
]
lint = [
  "ruff"
]

Once groups are defined, the --all-groups, --no-default-groups, --group, --only-group, and --no-group options can be used to include or exclude their dependencies.

!!! tip

The `--dev`, `--only-dev`, and `--no-dev` flags are equivalent to `--group dev`,
`--only-group dev`, and `--no-group dev` respectively.

uv requires that all dependency groups are compatible with each other and resolves all groups together when creating the lockfile.

If dependencies declared in one group are not compatible with those in another group, uv will fail to resolve the requirements of the project with an error.

!!! note

If you have dependency groups that conflict with one another, resolution will fail
unless you explicitly [declare them as conflicting](./config.md#conflicting-dependencies).

Default groups

By default, uv includes the dev dependency group in the environment (e.g., during uv run or uv sync). The default groups to include can be changed using the tool.uv.default-groups setting.

[tool.uv]
default-groups = ["dev", "foo"]

To enable all dependencies groups by default, use "all" instead of listing group names:

[tool.uv]
default-groups = "all"

!!! tip

To disable this behaviour during `uv run` or `uv sync`, use `--no-default-groups`.
To exclude a specific default group, use `--no-group <name>`.

Legacy dev-dependencies

Before [dependency-groups] was standardized, uv used the tool.uv.dev-dependencies field to specify development dependencies, e.g.:

[tool.uv]
dev-dependencies = [
  "pytest"
]

Dependencies declared in this section will be combined with the contents in the dependency-groups.dev. Eventually, the dev-dependencies field will be deprecated and removed.

!!! note

If a `tool.uv.dev-dependencies` field exists, `uv add --dev` will use the existing section
instead of adding a new `dependency-groups.dev` section.

Build dependencies

If a project is structured as Python package, it may declare dependencies that are required to build the project, but not required to run it. These dependencies are specified in the [build-system] table under build-system.requires, following PEP 518.

For example, if a project uses setuptools as its build backend, it should declare setuptools as a build dependency:

[project]
name = "pandas"
version = "0.1.0"

[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"

By default, uv will respect tool.uv.sources when resolving build dependencies. For example, to use a local version of setuptools for building, add the source to tool.uv.sources:

[project]
name = "pandas"
version = "0.1.0"

[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"

[tool.uv.sources]
setuptools = { path = "./packages/setuptools" }

When publishing a package, we recommend running uv build --no-sources to ensure that the package builds correctly when tool.uv.sources is disabled, as is the case when using other build tools, like pypa/build.

Editable dependencies

A regular installation of a directory with a Python package first builds a wheel and then installs that wheel into your virtual environment, copying all source files. When the package source files are edited, the virtual environment will contain outdated versions.

Editable installations solve this problem by adding a link to the project within the virtual environment (a .pth file), which instructs the interpreter to include the source files directly.

There are some limitations to editables (mainly: the build backend needs to support them, and native modules aren't recompiled before import), but they are useful for development, as the virtual environment will always use the latest changes to the package.

uv uses editable installation for workspace packages by default.

To add an editable dependency, use the --editable flag:

$ uv add --editable ./path/foo

Or, to opt-out of using an editable dependency in a workspace:

$ uv add --no-editable ./path/foo

Dependency specifiers (PEP 508)

uv uses dependency specifiers, previously known as PEP 508. A dependency specifier is composed of, in order:

  • The dependency name
  • The extras you want (optional)
  • The version specifier
  • An environment marker (optional)

The version specifiers are comma separated and added together, e.g., foo >=1.2.3,<2,!=1.4.0 is interpreted as "a version of foo that's at least 1.2.3, but less than 2, and not 1.4.0".

Specifiers are padded with trailing zeros if required, so foo ==2 matches foo 2.0.0, too.

A star can be used for the last digit with equals, e.g., foo ==2.1.* will accept any release from the 2.1 series. Similarly, ~= matches where the last digit is equal or higher, e.g., foo ~=1.2 is equal to foo >=1.2,<2, and foo ~=1.2.3 is equal to foo >=1.2.3,<1.3.

Extras are comma-separated in square bracket between name and version, e.g., pandas[excel,plot] ==2.2. Whitespace between extra names is ignored.

Some dependencies are only required in specific environments, e.g., a specific Python version or operating system. For example to install the importlib-metadata backport for the importlib.metadata module, use importlib-metadata >=7.1.0,<8; python_version < '3.10'. To install colorama on Windows (but omit it on other platforms), use colorama >=0.4.6,<5; platform_system == "Windows".

Markers are combined with and, or, and parentheses, e.g., aiohttp >=3.7.4,<4; (sys_platform != 'win32' or implementation_name != 'pypy') and python_version >= '3.10'. Note that versions within markers must be quoted, while versions outside of markers must not be quoted.