# TLS certificates

By default, uv loads certificates from the bundled `webpki-roots` crate. The `webpki-roots` are a
reliable set of trust roots from Mozilla, and including them in uv improves portability and
performance (especially on macOS, where reading the system trust store incurs a significant delay).

## System certificates

In some cases, you may want to use the platform's native certificate store, especially if you're
relying on a corporate trust root (e.g., for a mandatory proxy) that's included in your system's
certificate store. To instruct uv to use the system's trust store, run uv with the `--native-tls`
command-line flag, or set the `UV_NATIVE_TLS` environment variable to `true`.

## Custom certificates

If a direct path to the certificate is required (e.g., in CI), set the `SSL_CERT_FILE` environment
variable to the path of the certificate bundle, to instruct uv to use that file instead of the
system's trust store.

If client certificate authentication (mTLS) is desired, set the `SSL_CLIENT_CERT` environment
variable to the path of the PEM formatted file containing the certificate followed by the private
key.

## Insecure hosts

If you're using a setup in which you want to trust a self-signed certificate or otherwise disable
certificate verification, you can instruct uv to allow insecure connections to dedicated hosts via
the `allow-insecure-host` configuration option. For example, adding the following to
`pyproject.toml` will allow insecure connections to `example.com`:

```toml
[tool.uv]
allow-insecure-host = ["example.com"]
```

`allow-insecure-host` expects to receive a hostname (e.g., `localhost`) or hostname-port pair (e.g.,
`localhost:8080`), and is only applicable to HTTPS connections, as HTTP connections are inherently
insecure.

Use `allow-insecure-host` with caution and only in trusted environments, as it can expose you to
security risks due to the lack of certificate verification.

    # Git credentials

uv allows packages to be installed from private Git repositories using SSH or HTTP authentication.

## SSH authentication

To authenticate using an SSH key, use the `ssh://` protocol:

- `git+ssh://git@<hostname>/...` (e.g., `git+ssh://git@github.com/astral-sh/uv`)
- `git+ssh://git@<host>/...` (e.g., `git+ssh://git@github.com-key-2/astral-sh/uv`)

SSH authentication requires using the username `git`.

See the
[GitHub SSH documentation](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/about-ssh)
for more details on how to configure SSH.

### HTTP authentication

To authenticate over HTTP Basic authentication using a password or token:

- `git+https://<user>:<token>@<hostname>/...` (e.g.,
  `git+https://git:github_pat_asdf@github.com/astral-sh/uv`)
- `git+https://<token>@<hostname>/...` (e.g., `git+https://github_pat_asdf@github.com/astral-sh/uv`)
- `git+https://<user>@<hostname>/...` (e.g., `git+https://git@github.com/astral-sh/uv`)

!!! note

    When using a GitHub personal access token, the username is arbitrary. GitHub doesn't allow you to
    use your account name and password in URLs like this, although other hosts may.

If there are no credentials present in the URL and authentication is needed, the
[Git credential helper](#git-credential-helpers) will be queried.

## Persistence of credentials

When using `uv add`, uv _will not_ persist Git credentials to the `pyproject.toml` or `uv.lock`.
These files are often included in source control and distributions, so it is generally unsafe to
include credentials in them.

If you have a Git credential helper configured, your credentials may be automatically persisted,
resulting in successful subsequent fetches of the dependency. However, if you do not have a Git
credential helper or the project is used on a machine without credentials seeded, uv will fail to
fetch the dependency.

You _may_ force uv to persist Git credentials by passing the `--raw` option to `uv add`. However, we
strongly recommend setting up a [credential helper](#git-credential-helpers) instead.

## Git credential helpers

Git credential helpers are used to store and retrieve Git credentials. See the
[Git documentation](https://git-scm.com/doc/credential-helpers) to learn more.

If you're using GitHub, the simplest way to set up a credential helper is to
[install the `gh` CLI](https://github.com/cli/cli#installation) and use:

```console
$ gh auth login
```

See the [`gh auth login`](https://cli.github.com/manual/gh_auth_login) documentation for more
details.

!!! note

    When using `gh auth login` interactively, the credential helper will be configured automatically.
    But when using `gh auth login --with-token`, as in the uv
    [GitHub Actions guide](../../guides/integration/github.md#private-repos), the
    [`gh auth setup-git`](https://cli.github.com/manual/gh_auth_setup-git) command will need to be
    run afterwards to configure the credential helper.

    # HTTP credentials

uv supports credentials over HTTP when querying package registries.

Authentication can come from the following sources, in order of precedence:

- The URL, e.g., `https://<user>:<password>@<hostname>/...`
- A [netrc](#netrc-files) configuration file
- The uv credentials store
- A [keyring provider](#keyring-providers) (off by default)

Authentication may be used for hosts specified in the following contexts:

- `[index]`
- `index-url`
- `extra-index-url`
- `find-links`
- `package @ https://...`

## netrc files

[`.netrc`](https://everything.curl.dev/usingcurl/netrc) files are a long-standing plain text format
for storing credentials on a system.

Reading credentials from `.netrc` files is always enabled. The target file path will be loaded from
the `NETRC` environment variable if defined, falling back to `~/.netrc` if not.

## The uv credentials store

uv can read and write credentials from a store using the [`uv auth` commands](./cli.md).

Credentials are stored in a plaintext file in uv's state directory, e.g.,
`~/.local/share/uv/credentials/credentials.toml` on Unix. This file is currently not intended to be
edited manually.

!!! note

    A secure, system native storage mechanism is in [preview](../preview.md) — it is still
    experimental and being actively developed. In the future, this will become the default storage
    mechanism.

    When enabled, uv will use the secret storage mechanism native to your operating system. On
    macOS, it uses the Keychain Services. On Windows, it uses the Windows Credential Manager. On
    Linux, it uses the DBus-based Secret Service API.

    Currently, uv only searches the native store for credentials it has added to the secret store —
    it will not retrieve credentials persisted by other applications.

    Set `UV_PREVIEW_FEATURES=native-auth` to use this storage mechanism.

## Keyring providers

A keyring provider is a concept from `pip` allowing retrieval of credentials from an interface
matching the popular [keyring](https://github.com/jaraco/keyring) Python package.

The "subprocess" keyring provider invokes the `keyring` command to fetch credentials. uv does not
support additional keyring provider types at this time.

Set `--keyring-provider subprocess`, `UV_KEYRING_PROVIDER=subprocess`, or
`tool.uv.keyring-provider = "subprocess"` to use the provider.

## Persistence of credentials

If authentication is found for a single index URL or net location (scheme, host, and port), it will
be cached for the duration of the command and used for other queries to that index or net location.
Authentication is not cached across invocations of uv.

When using `uv add`, uv _will not_ persist index credentials to the `pyproject.toml` or `uv.lock`.
These files are often included in source control and distributions, so it is generally unsafe to
include credentials in them. However, uv _will_ persist credentials for direct URLs, i.e.,
`package @ https://username:password:example.com/foo.whl`, as there is not currently a way to
otherwise provide those credentials.

If credentials were attached to an index URL during `uv add`, uv may fail to fetch dependencies from
indexes which require authentication on subsequent operations. See the
[index authentication documentation](../indexes.md#authentication) for details on persistent
authentication for indexes.

## Learn more

See the [index authentication documentation](../indexes.md#authentication) for details on
authenticating index URLs.

See the [`pip` compatibility guide](../../pip/compatibility.md#registry-authentication) for details
on differences from `pip`.

    # Authentication

Authentication is required when working with private repositories or package indexes.

Learn more about authentication in uv:

- [Using the `uv auth` CLI](./cli.md)
- [HTTP authentication](./http.md)
- [Git authentication](./git.md)
- [TLS certificates](./certificates.md)
- [Third-party services](./third-party.md)

    # Third-party services

## Authentication with alternative package indexes

See the [alternative indexes integration guide](../../guides/integration/alternative-indexes.md) for
details on authentication with popular alternative Python package indexes.

## Hugging Face support

uv supports automatic authentication for the Hugging Face Hub. Specifically, if the `HF_TOKEN`
environment variable is set, uv will propagate it to requests to `huggingface.co`.

This is particularly useful for accessing private scripts in Hugging Face Datasets. For example, you
can run the following command to execute the script `main.py` script from a private dataset:

```console
$ HF_TOKEN=hf_... uv run https://huggingface.co/datasets/<user>/<name>/resolve/<branch>/main.py
```

You can disable automatic Hugging Face authentication by setting the `UV_NO_HF_TOKEN=1` environment
variable.

    # The uv build backend

A build backend transforms a source tree (i.e., a directory) into a source distribution or a wheel.

uv supports all build backends (as specified by [PEP 517](https://peps.python.org/pep-0517/)), but
also provides a native build backend (`uv_build`) that integrates tightly with uv to improve
performance and user experience.

## Choosing a build backend

The uv build backend is a great choice for most Python projects. It has reasonable defaults, with
the goal of requiring zero configuration for most users, but provides flexible configuration to
accommodate most Python project structures. It integrates tightly with uv, to improve messaging and
user experience. It validates project metadata and structures, preventing common mistakes. And,
finally, it's very fast.

The uv build backend currently **only supports pure Python code**. An alternative backend is
required to build a
[library with extension modules](../concepts/projects/init.md#projects-with-extension-modules).

!!! tip

    While the backend supports a number of options for configuring your project structure, when build scripts or
    a more flexible project layout are required, consider using the
    [hatchling](https://hatch.pypa.io/latest/config/build/#build-system) build backend instead.

## Using the uv build backend

To use uv as a build backend in an existing project, add `uv_build` to the
[`[build-system]`](../concepts/projects/config.md#build-systems) section in your `pyproject.toml`:

```toml title="pyproject.toml"
[build-system]
requires = ["uv_build>=0.8.22,<0.9.0"]
build-backend = "uv_build"
```

!!! note

    The uv build backend follows the same [versioning policy](../reference/policies/versioning.md)
    as uv. Including an upper bound on the `uv_build` version ensures that your package continues to
    build correctly as new versions are released.

To create a new project that uses the uv build backend, use `uv init`:

```console
$ uv init
```

When the project is built, e.g., with [`uv build`](../guides/package.md), the uv build backend will
be used to create the source distribution and wheel.

## Bundled build backend

The build backend is published as a separate package (`uv_build`) that is optimized for portability
and small binary size. However, the `uv` executable also includes a copy of the build backend, which
will be used during builds performed by uv, e.g., during `uv build`, if its version is compatible
with the `uv_build` requirement. If it's not compatible, a compatible version of the `uv_build`
package will be used. Other build frontends, such as `python -m build`, will always use the
`uv_build` package, typically choosing the latest compatible version.

## Modules

Python packages are expected to contain one or more Python modules, which are directories containing
an `__init__.py`. By default, a single root module is expected at `src/<package_name>/__init__.py`.

For example, the structure for a project named `foo` would be:

```text
pyproject.toml
src
└── foo
    └── __init__.py
```

uv normalizes the package name to determine the default module name: the package name is lowercased
and dots and dashes are replaced with underscores, e.g., `Foo-Bar` would be converted to `foo_bar`.

The `src/` directory is the default directory for module discovery.

These defaults can be changed with the `module-name` and `module-root` settings. For example, to use
a `FOO` module in the root directory, as in the project structure:

```text
pyproject.toml
FOO
└── __init__.py
```

The correct build configuration would be:

```toml title="pyproject.toml"
[tool.uv.build-backend]
module-name = "FOO"
module-root = ""
```

## Namespace packages

Namespace packages are intended for use-cases where multiple packages write modules into a shared
namespace.

Namespace package modules are identified by a `.` in the `module-name`. For example, to package the
module `bar` in the shared namespace `foo`, the project structure would be:

```text
pyproject.toml
src
└── foo
    └── bar
        └── __init__.py
```

And the `module-name` configuration would be:

```toml title="pyproject.toml"
[tool.uv.build-backend]
module-name = "foo.bar"
```

!!! important

    The `__init__.py` file is not included in `foo`, since it's the shared namespace module.

It's also possible to have a complex namespace package with more than one root module, e.g., with
the project structure:

```text
pyproject.toml
src
├── foo
│   └── __init__.py
└── bar
    └── __init__.py
```

While we do not recommend this structure (i.e., you should use a workspace with multiple packages
instead), it is supported by setting `module-name` to a list of names:

```toml title="pyproject.toml"
[tool.uv.build-backend]
module-name = ["foo", "bar"]
```

For packages with many modules or complex namespaces, the `namespace = true` option can be used to
avoid explicitly declaring each module name, e.g.:

```toml title="pyproject.toml"
[tool.uv.build-backend]
namespace = true
```

!!! warning

    Using `namespace = true` disables safety checks. Using an explicit list of module names is
    strongly recommended outside of legacy projects.

The `namespace` option can also be used with `module-name` to explicitly declare the root, e.g., for
the project structure:

```text
pyproject.toml
src
└── foo
    ├── bar
    │   └── __init__.py
    └── baz
        └── __init__.py
```

The recommended configuration would be:

```toml title="pyproject.toml"
[tool.uv.build-backend]
module-name = "foo"
namespace = true
```

## Stub packages

The build backend also supports building type stub packages, which are identified by the `-stubs`
suffix on the package or module name, e.g., `foo-stubs`. The module name for type stub packages must
end in `-stubs`, so uv will not normalize the `-` to an underscore. Additionally, uv will search for
a `__init__.pyi` file. For example, the project structure would be:

```text
pyproject.toml
src
└── foo-stubs
    └── __init__.pyi
```

Type stub modules are also supported for [namespace packages](#namespace-packages).

## File inclusion and exclusion

The build backend is responsible for determining which files in a source tree should be packaged
into the distributions.

To determine which files to include in a source distribution, uv first adds the included files and
directories, then removes the excluded files and directories. This means that exclusions always take
precedence over inclusions.

By default, uv excludes `__pycache__`, `*.pyc`, and `*.pyo`.

When building a source distribution, the following files and directories are included:

- The `pyproject.toml`
- The [module](#modules) under
  [`tool.uv.build-backend.module-root`](../reference/settings.md#build-backend_module-root).
- The files referenced by `project.license-files` and `project.readme`.
- All directories under [`tool.uv.build-backend.data`](../reference/settings.md#build-backend_data).
- All files matching patterns from
  [`tool.uv.build-backend.source-include`](../reference/settings.md#build-backend_source-include).

From these, items matching
[`tool.uv.build-backend.source-exclude`](../reference/settings.md#build-backend_source-exclude) and
the [default excludes](../reference/settings.md#build-backend_default-excludes) are removed.

When building a wheel, the following files and directories are included:

- The [module](#modules) under
  [`tool.uv.build-backend.module-root`](../reference/settings.md#build-backend_module-root)
- The files referenced by `project.license-files`, which are copied into the `.dist-info` directory.
- The `project.readme`, which is copied into the project metadata.
- All directories under [`tool.uv.build-backend.data`](../reference/settings.md#build-backend_data),
  which are copied into the `.data` directory.

From these,
[`tool.uv.build-backend.source-exclude`](../reference/settings.md#build-backend_source-exclude),
[`tool.uv.build-backend.wheel-exclude`](../reference/settings.md#build-backend_wheel-exclude) and
the default excludes are removed. The source dist excludes are applied to avoid source tree to wheel
source builds including more files than source tree to source distribution to wheel build.

There are no specific wheel includes. There must only be one top level module, and all data files
must either be under the module root or in the appropriate
[data directory](../reference/settings.md#build-backend_data). Most packages store small data in the
module root alongside the source code.

!!! tip

    When using the uv build backend through a frontend that is not uv, such as pip or
    `python -m build`, debug logging can be enabled through environment variables with
    `RUST_LOG=uv=debug` or `RUST_LOG=uv=verbose`. When used through uv, the uv build backend shares
    the verbosity level of uv.

### Include and exclude syntax

Includes are anchored, which means that `pyproject.toml` includes only `<root>/pyproject.toml` and
not `<root>/bar/pyproject.toml`. To recursively include all files under a directory, use a `/**`
suffix, e.g. `src/**`. Recursive inclusions are also anchored, e.g., `assets/**/sample.csv` includes
all `sample.csv` files in `<root>/assets` or any of its children.

!!! note

    For performance and reproducibility, avoid patterns without an anchor such as `**/sample.csv`.

Excludes are not anchored, which means that `__pycache__` excludes all directories named
`__pycache__` regardless of its parent directory. All children of an exclusion are excluded as well.
To anchor a directory, use a `/` prefix, e.g., `/dist` will exclude only `<root>/dist`.

All fields accepting patterns use the reduced portable glob syntax from
[PEP 639](https://peps.python.org/pep-0639/#add-license-FILES-key), with the addition that
characters can be escaped with a backslash.

    # Caching

## Dependency caching

uv uses aggressive caching to avoid re-downloading (and re-building) dependencies that have already
been accessed in prior runs.

The specifics of uv's caching semantics vary based on the nature of the dependency:

- **For registry dependencies** (like those downloaded from PyPI), uv respects HTTP caching headers.
- **For direct URL dependencies**, uv respects HTTP caching headers, and also caches based on the
  URL itself.
- **For Git dependencies**, uv caches based on the fully-resolved Git commit hash. As such,
  `uv pip compile` will pin Git dependencies to a specific commit hash when writing the resolved
  dependency set.
- **For local dependencies**, uv caches based on the last-modified time of the source archive (i.e.,
  the local `.whl` or `.tar.gz` file). For directories, uv caches based on the last-modified time of
  the `pyproject.toml`, `setup.py`, or `setup.cfg` file.

If you're running into caching issues, uv includes a few escape hatches:

- To clear the cache entirely, run `uv cache clean`. To clear the cache for a specific package, run
  `uv cache clean <package-name>`. For example, `uv cache clean ruff` will clear the cache for the
  `ruff` package.
- To force uv to revalidate cached data for all dependencies, pass `--refresh` to any command (e.g.,
  `uv sync --refresh` or `uv pip install --refresh ...`).
- To force uv to revalidate cached data for a specific dependency pass `--refresh-package` to any
  command (e.g., `uv sync --refresh-package ruff` or `uv pip install --refresh-package ruff ...`).
- To force uv to ignore existing installed versions, pass `--reinstall` to any installation command
  (e.g., `uv sync --reinstall` or `uv pip install --reinstall ...`). (Consider running
  `uv cache clean <package-name>` first, to ensure that the cache is cleared prior to
  reinstallation.)

As a special case, uv will always rebuild and reinstall any local directory dependencies passed
explicitly on the command-line (e.g., `uv pip install .`).

## Dynamic metadata

By default, uv will _only_ rebuild and reinstall local directory dependencies (e.g., editables) if
the `pyproject.toml`, `setup.py`, or `setup.cfg` file in the directory root has changed, or if a
`src` directory is added or removed. This is a heuristic and, in some cases, may lead to fewer
re-installs than desired.

To incorporate additional information into the cache key for a given package, you can add cache key
entries under [`tool.uv.cache-keys`](https://docs.astral.sh/uv/reference/settings/#cache-keys),
which covers both file paths and Git commit hashes. Setting
[`tool.uv.cache-keys`](https://docs.astral.sh/uv/reference/settings/#cache-keys) will replace
defaults, so any necessary files (like `pyproject.toml`) should still be included in the
user-defined cache keys.

For example, if a project specifies dependencies in `pyproject.toml` but uses
[`setuptools-scm`](https://pypi.org/project/setuptools-scm/) to manage its version, and should thus
be rebuilt whenever the commit hash or dependencies change, you can add the following to the
project's `pyproject.toml`:

```toml title="pyproject.toml"
[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { git = { commit = true } }]
```

If your dynamic metadata incorporates information from the set of Git tags, you can expand the cache
key to include the tags:

```toml title="pyproject.toml"
[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { git = { commit = true, tags = true } }]
```

Similarly, if a project reads from a `requirements.txt` to populate its dependencies, you can add
the following to the project's `pyproject.toml`:

```toml title="pyproject.toml"
[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { file = "requirements.txt" }]
```

Globs are supported for `file` keys, following the syntax of the
[`glob`](https://docs.rs/glob/0.3.1/glob/struct.Pattern.html) crate. For example, to invalidate the
cache whenever a `.toml` file in the project directory or any of its subdirectories is modified, use
the following:

```toml title="pyproject.toml"
[tool.uv]
cache-keys = [{ file = "**/*.toml" }]
```

!!! note

    The use of globs can be expensive, as uv may need to walk the filesystem to determine whether any files have changed.
    This may, in turn, requiring traversal of large or deeply nested directories.

Similarly, if a project relies on an environment variable, you can add the following to the
project's `pyproject.toml` to invalidate the cache whenever the environment variable changes:

```toml title="pyproject.toml"
[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { env = "MY_ENV_VAR" }]
```

Finally, to invalidate a project whenever a specific directory (like `src`) is created or removed,
add the following to the project's `pyproject.toml`:

```toml title="pyproject.toml"
[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { dir = "src" }]
```

Note that the `dir` key will only track changes to the directory itself, and not arbitrary changes
within the directory.

As an escape hatch, if a project uses `dynamic` metadata that isn't covered by `tool.uv.cache-keys`,
you can instruct uv to _always_ rebuild and reinstall it by adding the project to the
`tool.uv.reinstall-package` list:

```toml title="pyproject.toml"
[tool.uv]
reinstall-package = ["my-package"]
```

This will force uv to rebuild and reinstall `my-package` on every run, regardless of whether the
package's `pyproject.toml`, `setup.py`, or `setup.cfg` file has changed.

## Cache safety

It's safe to run multiple uv commands concurrently, even against the same virtual environment. uv's
cache is designed to be thread-safe and append-only, and thus robust to multiple concurrent readers
and writers. uv applies a file-based lock to the target virtual environment when installing, to
avoid concurrent modifications across processes.

Note that it's _not_ safe to modify the uv cache (e.g., `uv cache clean`) while other uv commands
are running, and _never_ safe to modify the cache directly (e.g., by removing a file or directory).

## Clearing the cache

uv provides a few different mechanisms for removing entries from the cache:

- `uv cache clean` removes _all_ cache entries from the cache directory, clearing it out entirely.
- `uv cache clean ruff` removes all cache entries for the `ruff` package, useful for invalidating
  the cache for a single or finite set of packages.
- `uv cache prune` removes all _unused_ cache entries. For example, the cache directory may contain
  entries created in previous uv versions that are no longer necessary and can be safely removed.
  `uv cache prune` is safe to run periodically, to keep the cache directory clean.

## Caching in continuous integration

It's common to cache package installation artifacts in continuous integration environments (like
GitHub Actions or GitLab CI) to speed up subsequent runs.

By default, uv caches both the wheels that it builds from source and the pre-built wheels that it
downloads directly, to enable high-performance package installation.

However, in continuous integration environments, persisting pre-built wheels may be undesirable.
With uv, it turns out that it's often faster to _omit_ pre-built wheels from the cache (and instead
re-download them from the registry on each run). On the other hand, caching wheels that are built
from source tends to be worthwhile, since the wheel building process can be expensive, especially
for extension modules.

To support this caching strategy, uv provides a `uv cache prune --ci` command, which removes all
pre-built wheels and unzipped source distributions from the cache, but retains any wheels that were
built from source. We recommend running `uv cache prune --ci` at the end of your continuous
integration job to ensure maximum cache efficiency. For an example, see the
[GitHub integration guide](../guides/integration/github.md#caching).

## Cache directory

uv determines the cache directory according to, in order:

1. A temporary cache directory, if `--no-cache` was requested.
2. The specific cache directory specified via `--cache-dir`, `UV_CACHE_DIR`, or
   [`tool.uv.cache-dir`](../reference/settings.md#cache-dir).
3. A system-appropriate cache directory, e.g., `$XDG_CACHE_HOME/uv` or `$HOME/.cache/uv` on Unix and
   `%LOCALAPPDATA%\uv\cache` on Windows

!!! note

    uv _always_ requires a cache directory. When `--no-cache` is requested, uv will still use
    a temporary cache for sharing data within that single invocation.

    In most cases, `--refresh` should be used instead of `--no-cache` — as it will update the cache
    for subsequent operations but not read from the cache.

It is important for performance for the cache directory to be located on the same file system as the
Python environment uv is operating on. Otherwise, uv will not be able to link files from the cache
into the environment and will instead need to fallback to slow copy operations.

## Cache versioning

The uv cache is composed of a number of buckets (e.g., a bucket for wheels, a bucket for source
distributions, a bucket for Git repositories, and so on). Each bucket is versioned, such that if a
release contains a breaking change to the cache format, uv will not attempt to read from or write to
an incompatible cache bucket.

For example, uv 0.4.13 included a breaking change to the core metadata bucket. As such, the bucket
version was increased from v12 to v13. Within a cache version, changes are guaranteed to be both
forwards- and backwards-compatible.

Since changes in the cache format are accompanied by changes in the cache version, multiple versions
of uv can safely read and write to the same cache directory. However, if the cache version changed
between a given pair of uv releases, then those releases may not be able to share the same
underlying cache entries.

For example, it's safe to use a single shared cache for uv 0.4.12 and uv 0.4.13, though the cache
itself may contain duplicate entries in the core metadata bucket due to the change in cache version.

    # Configuration files

uv supports persistent configuration files at both the project- and user-level.

Specifically, uv will search for a `pyproject.toml` or `uv.toml` file in the current directory, or
in the nearest parent directory.

!!! note

    For `tool` commands, which operate at the user level, local configuration
    files will be ignored. Instead, uv will exclusively read from user-level configuration
    (e.g., `~/.config/uv/uv.toml`) and system-level configuration (e.g., `/etc/uv/uv.toml`).

In workspaces, uv will begin its search at the workspace root, ignoring any configuration defined in
workspace members. Since the workspace is locked as a single unit, configuration is shared across
all members.

If a `pyproject.toml` file is found, uv will read configuration from the `[tool.uv]` table. For
example, to set a persistent index URL, add the following to a `pyproject.toml`:

```toml title="pyproject.toml"
[[tool.uv.index]]
url = "https://test.pypi.org/simple"
default = true
```

(If there is no such table, the `pyproject.toml` file will be ignored, and uv will continue
searching in the directory hierarchy.)

uv will also search for `uv.toml` files, which follow an identical structure, but omit the
`[tool.uv]` prefix. For example:

```toml title="uv.toml"
[[index]]
url = "https://test.pypi.org/simple"
default = true
```

!!! note

    `uv.toml` files take precedence over `pyproject.toml` files, so if both `uv.toml` and
    `pyproject.toml` files are present in a directory, configuration will be read from `uv.toml`, and
    `[tool.uv]` section in the accompanying `pyproject.toml` will be ignored.

uv will also discover user-level configuration at `~/.config/uv/uv.toml` (or
`$XDG_CONFIG_HOME/uv/uv.toml`) on macOS and Linux, or `%APPDATA%\uv\uv.toml` on Windows; and
system-level configuration at `/etc/uv/uv.toml` (or `$XDG_CONFIG_DIRS/uv/uv.toml`) on macOS and
Linux, or `%SYSTEMDRIVE%\ProgramData\uv\uv.toml` on Windows.

User-and system-level configuration must use the `uv.toml` format, rather than the `pyproject.toml`
format, as a `pyproject.toml` is intended to define a Python _project_.

If project-, user-, and system-level configuration files are found, the settings will be merged,
with project-level configuration taking precedence over the user-level configuration, and user-level
configuration taking precedence over the system-level configuration. (If multiple system-level
configuration files are found, e.g., at both `/etc/uv/uv.toml` and `$XDG_CONFIG_DIRS/uv/uv.toml`,
only the first-discovered file will be used, with XDG taking priority.)

For example, if a string, number, or boolean is present in both the project- and user-level
configuration tables, the project-level value will be used, and the user-level value will be
ignored. If an array is present in both tables, the arrays will be concatenated, with the
project-level settings appearing earlier in the merged array.

Settings provided via environment variables take precedence over persistent configuration, and
settings provided via the command line take precedence over both.

uv accepts a `--no-config` command-line argument which, when provided, disables the discovery of any
persistent configuration.

uv also accepts a `--config-file` command-line argument, which accepts a path to a `uv.toml` to use
as the configuration file. When provided, this file will be used in place of _any_ discovered
configuration files (e.g., user-level configuration will be ignored).

## Settings

See the [settings reference](../reference/settings.md) for an enumeration of the available settings.

## `.env`

`uv run` can load environment variables from dotenv files (e.g., `.env`, `.env.local`,
`.env.development`), powered by the [`dotenvy`](https://github.com/allan2/dotenvy) crate.

To load a `.env` file from a dedicated location, set the `UV_ENV_FILE` environment variable, or pass
the `--env-file` flag to `uv run`.

For example, to load environment variables from a `.env` file in the current working directory:

```console
$ echo "MY_VAR='Hello, world!'" > .env
$ uv run --env-file .env -- python -c 'import os; print(os.getenv("MY_VAR"))'
Hello, world!
```

The `--env-file` flag can be provided multiple times, with subsequent files overriding values
defined in previous files. To provide multiple files via the `UV_ENV_FILE` environment variable,
separate the paths with a space (e.g., `UV_ENV_FILE="/path/to/file1 /path/to/file2"`).

To disable dotenv loading (e.g., to override `UV_ENV_FILE` or the `--env-file` command-line
argument), set the `UV_NO_ENV_FILE` environment variable to `1`, or pass the`--no-env-file` flag to
`uv run`.

If the same variable is defined in the environment and in a `.env` file, the value from the
environment will take precedence.

## Configuring the pip interface

A dedicated [`[tool.uv.pip]`](../reference/settings.md#pip) section is provided for configuring
_just_ the `uv pip` command line interface. Settings in this section will not apply to `uv` commands
outside the `uv pip` namespace. However, many of the settings in this section have corollaries in
the top-level namespace which _do_ apply to the `uv pip` interface unless they are overridden by a
value in the `uv.pip` section.

The `uv.pip` settings are designed to adhere closely to pip's interface and are declared separately
to retain compatibility while allowing the global settings to use alternate designs (e.g.,
`--no-build`).

As an example, setting the `index-url` under `[tool.uv.pip]`, as in the following `pyproject.toml`,
would only affect the `uv pip` subcommands (e.g., `uv pip install`, but not `uv sync`, `uv lock`, or
`uv run`):

```toml title="pyproject.toml"
[tool.uv.pip]
index-url = "https://test.pypi.org/simple"
```

    # Concepts overview

Read the concept documents to learn more about uv's features:

- [Projects](./projects/index.md)
- [Tools](./tools.md)
- [Python versions](./python-versions.md)
- [Configuration files](./configuration-files.md)
- [Package indexes](./indexes.md)
- [Resolution](./resolution.md)
- [The uv build backend](./build-backend.md)
- [Authentication](./authentication/index.md)
- [Caching](./cache.md)
- [The pip interface](../pip/index.md)

Looking for a quick introduction to features? See the [guides](../guides/index.md) instead.

    # Package indexes

By default, uv uses the [Python Package Index (PyPI)](https://pypi.org) for dependency resolution
and package installation. However, uv can be configured to use other package indexes, including
private indexes, via the `[[tool.uv.index]]` configuration option (and `--index`, the analogous
command-line option).

## Defining an index

To include an additional index when resolving dependencies, add a `[[tool.uv.index]]` entry to your
`pyproject.toml`:

```toml
[[tool.uv.index]]
# Optional name for the index.
name = "pytorch"
# Required URL for the index.
url = "https://download.pytorch.org/whl/cpu"
```

Indexes are prioritized in the order in which they’re defined, such that the first index listed in
the configuration file is the first index consulted when resolving dependencies, with indexes
provided via the command line taking precedence over those in the configuration file.

By default, uv includes the Python Package Index (PyPI) as the "default" index, i.e., the index used
when a package is not found on any other index. To exclude PyPI from the list of indexes, set
`default = true` on another index entry (or use the `--default-index` command-line option):

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

The default index is always treated as lowest priority, regardless of its position in the list of
indexes.

Index names may only contain alphanumeric characters, dashes, underscores, and periods, and must be
valid ASCII.

When providing an index on the command line (with `--index` or `--default-index`) or through an
environment variable (`UV_INDEX` or `UV_DEFAULT_INDEX`), names are optional but can be included
using the `<name>=<url>` syntax, as in:

```shell
# On the command line.
$ uv lock --index pytorch=https://download.pytorch.org/whl/cpu
# Via an environment variable.
$ UV_INDEX=pytorch=https://download.pytorch.org/whl/cpu uv lock
```

## Pinning a package to an index

A package can be pinned to a specific index by specifying the index in its `tool.uv.sources` entry.
For example, to ensure that `torch` is _always_ installed from the `pytorch` index, add the
following to your `pyproject.toml`:

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

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

Similarly, to pull from a different index based on the platform, you can provide a list of sources
disambiguated by environment markers:

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

[tool.uv.sources]
torch = [
  { index = "pytorch-cu118", marker = "sys_platform == 'darwin'"},
  { index = "pytorch-cu124", marker = "sys_platform != 'darwin'"},
]

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

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

An index can be marked as `explicit = true` to prevent packages from being installed from that index
unless explicitly pinned to it. For example, to ensure that `torch` is installed from the `pytorch`
index, but all other packages are installed from PyPI, add the following to your `pyproject.toml`:

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

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

Named indexes referenced via `tool.uv.sources` must be defined within the project's `pyproject.toml`
file; indexes provided via the command-line, environment variables, or user-level configuration will
not be recognized.

If an index is marked as both `default = true` and `explicit = true`, it will be treated as an
explicit index (i.e., only usable via `tool.uv.sources`) while also removing PyPI as the default
index.

## Searching across multiple indexes

By default, uv will stop at the first index on which a given package is available, and limit
resolutions to those present on that first index (`first-index`).

For example, if an internal index is specified via `[[tool.uv.index]]`, uv's behavior is such that
if a package exists on that internal index, it will _always_ be installed from that internal index,
and never from PyPI. The intent is to prevent "dependency confusion" attacks, in which an attacker
publishes a malicious package on PyPI with the same name as an internal package, thus causing the
malicious package to be installed instead of the internal package. See, for example,
[the `torchtriton` attack](https://pytorch.org/blog/compromised-nightly-dependency/) from
December 2022.

To opt in to alternate index behaviors, use the`--index-strategy` command-line option, or the
`UV_INDEX_STRATEGY` environment variable, which supports the following values:

- `first-index` (default): Search for each package across all indexes, limiting the candidate
  versions to those present in the first index that contains the package.
- `unsafe-first-match`: Search for each package across all indexes, but prefer the first index with
  a compatible version, even if newer versions are available on other indexes.
- `unsafe-best-match`: Search for each package across all indexes, and select the best version from
  the combined set of candidate versions.

While `unsafe-best-match` is the closest to pip's behavior, it exposes users to the risk of
"dependency confusion" attacks.

## Authentication

Most private package indexes require authentication to access packages, typically via a username and
password (or access token).

!!! tip

    See the [alternative index guide](../guides/integration/alternative-indexes.md) for details on
    authenticating with specific private index providers, e.g., from AWS, Azure, or GCP.

### Providing credentials directly

Credentials can be provided directly via environment variables or by embedding them in the URL.

For example, given an index named `internal-proxy` that requires a username (`public`) and password
(`koala`), define the index (without credentials) in your `pyproject.toml`:

```toml
[[tool.uv.index]]
name = "internal-proxy"
url = "https://example.com/simple"
```

From there, you can set the `UV_INDEX_INTERNAL_PROXY_USERNAME` and
`UV_INDEX_INTERNAL_PROXY_PASSWORD` environment variables, where `INTERNAL_PROXY` is the uppercase
version of the index name, with non-alphanumeric characters replaced by underscores:

```sh
export UV_INDEX_INTERNAL_PROXY_USERNAME=public
export UV_INDEX_INTERNAL_PROXY_PASSWORD=koala
```

By providing credentials via environment variables, you can avoid storing sensitive information in
the plaintext `pyproject.toml` file.

Alternatively, credentials can be embedded directly in the index definition:

```toml
[[tool.uv.index]]
name = "internal"
url = "https://public:koala@pypi-proxy.corp.dev/simple"
```

For security purposes, credentials are _never_ stored in the `uv.lock` file; as such, uv _must_ have
access to the authenticated URL at installation time.

### Using credential providers

In addition to providing credentials directly, uv supports discovery of credentials from netrc and
keyring. See the [HTTP authentication](./authentication/http.md) documentation for details on
setting up specific credential providers.

By default, uv will attempt an unauthenticated request before querying providers. If the request
fails, uv will search for credentials. If credentials are found, an authenticated request will be
attempted.

!!! note

    If a username is set, uv will search for credentials before making an unauthenticated request.

Some indexes (e.g., GitLab) will forward unauthenticated requests to a public index, like PyPI —
which means that uv will not search for credentials. This behavior can be changed per-index, using
the `authenticate` setting. For example, to always search for credentials:

```toml hl_lines="4"
[[tool.uv.index]]
name = "example"
url = "https://example.com/simple"
authenticate = "always"
```

When `authenticate` is set to `always`, uv will eagerly search for credentials and error if
credentials cannot be found.

### Ignoring error codes when searching across indexes

When using the [first-index strategy](#searching-across-multiple-indexes), uv will stop searching
across indexes if an HTTP 401 Unauthorized or HTTP 403 Forbidden status code is encountered. The one
exception is that uv will ignore 403s when searching the `pytorch` index (since this index returns a
403 when a package is not present).

To configure which error codes are ignored for an index, use the `ignored-error-codes` setting. For
example, to ignore 403s (but not 401s) for a private index:

```toml
[[tool.uv.index]]
name = "private-index"
url = "https://private-index.com/simple"
authenticate = "always"
ignore-error-codes = [403]
```

uv will always continue searching across indexes when it encounters a `404 Not Found`. This cannot
be overridden.

### Disabling authentication

To prevent leaking credentials, authentication can be disabled for an index:

```toml hl_lines="4"
[[tool.uv.index]]
name = "example"
url = "https://example.com/simple"
authenticate = "never"
```

When `authenticate` is set to `never`, uv will never search for credentials for the given index and
will error if credentials are provided directly.

### Customizing cache control headers

By default, uv will respect the cache control headers provided by the index. For example, PyPI
serves package metadata with a `max-age=600` header, thereby allowing uv to cache package metadata
for 10 minutes; and wheels and source distributions with a `max-age=365000000, immutable` header,
thereby allowing uv to cache artifacts indefinitely.

To override the cache control headers for an index, use the `cache-control` setting:

```toml
[[tool.uv.index]]
name = "example"
url = "https://example.com/simple"
cache-control = { api = "max-age=600", files = "max-age=365000000, immutable" }
```

The `cache-control` setting accepts an object with two optional keys:

- `api`: Controls caching for Simple API requests (package metadata).
- `files`: Controls caching for artifact downloads (wheels and source distributions).

The values for these keys are strings that follow the
[HTTP Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)
syntax. For example, to force uv to always revalidate package metadata, set `api = "no-cache"`:

```toml
[[tool.uv.index]]
name = "example"
url = "https://example.com/simple"
cache-control = { api = "no-cache" }
```

This setting is most commonly used to override the default cache control headers for private indexes
that otherwise disable caching, often unintentionally. We typically recommend following PyPI's
approach to caching headers, i.e., setting `api = "max-age=600"` and
`files = "max-age=365000000, immutable"`.

## "Flat" indexes

By default, `[[tool.uv.index]]` entries are assumed to be PyPI-style registries that implement the
[PEP 503](https://peps.python.org/pep-0503/) Simple Repository API. However, uv also supports "flat"
indexes, which are local directories or HTML pages that contain flat lists of wheels and source
distributions. In pip, such indexes are specified using the `--find-links` option.

To define a flat index in your `pyproject.toml`, use the `format = "flat"` option:

```toml
[[tool.uv.index]]
name = "example"
url = "/path/to/directory"
format = "flat"
```

Flat indexes support the same feature set as Simple Repository API indexes (e.g.,
`explicit = true`); you can also pin a package to a flat index using `tool.uv.sources`.

## `--index-url` and `--extra-index-url`

In addition to the `[[tool.uv.index]]` configuration option, uv supports pip-style `--index-url` and
`--extra-index-url` command-line options for compatibility, where `--index-url` defines the default
index and `--extra-index-url` defines additional indexes.

These options can be used in conjunction with the `[[tool.uv.index]]` configuration option, and
follow the same prioritization rules:

- The default index is always treated as lowest priority, whether defined via the legacy
  `--index-url` argument, the recommended `--default-index` argument, or a `[[tool.uv.index]]` entry
  with `default = true`.
- Indexes are consulted in the order in which they’re defined, either via the legacy
  `--extra-index-url` argument, the recommended `--index` argument, or `[[tool.uv.index]]` entries.

In effect, `--index-url` and `--extra-index-url` can be thought of as unnamed `[[tool.uv.index]]`
entries, with `default = true` enabled for the former. In that context, `--index-url` maps to
`--default-index`, and `--extra-index-url` maps to `--index`.

    # Preview features

uv includes opt-in preview features to provide an opportunity for community feedback and increase
confidence that changes are a net-benefit before enabling them for everyone.

## Enabling preview features

To enable all preview features, use the `--preview` flag:

```console
$ uv run --preview ...
```

Or, set the `UV_PREVIEW` environment variable:

```console
$ UV_PREVIEW=1 uv run ...
```

To enable specific preview features, use the `--preview-features` flag:

```console
$ uv run --preview-features foo ...
```

The `--preview-features` flag can be repeated to enable multiple features:

```console
$ uv run --preview-features foo --preview-features bar ...
```

Or, features can be provided in a comma separated list:

```console
$ uv run --preview-features foo,bar ...
```

The `UV_PREVIEW_FEATURES` environment variable can be used similarly, e.g.:

```console
$ UV_PREVIEW_FEATURES=foo,bar uv run ...
```

For backwards compatibility, enabling preview features that do not exist will warn, but not error.

## Using preview features

Often, preview features can be used without changing any preview settings if the behavior change is
gated by some sort of user interaction, For example, while `pylock.toml` support is in preview, you
can use `uv pip install` with a `pylock.toml` file without additional configuration because
specifying the `pylock.toml` file indicates you want to use the feature. However, a warning will be
displayed that the feature is in preview. The preview feature can be enabled to silence the warning.

Other preview features change behavior without changes to your use of uv. For example, when the
`python-upgrade` feature is enabled, the default behavior of `uv python install` changes to allow uv
to upgrade Python versions transparently. This feature requires enabling the preview flag for proper
usage.

## Available preview features

The following preview features are available:

- `add-bounds`: Allows configuring the
  [default bounds for `uv add`](../reference/settings.md#add-bounds) invocations.
- `json-output`: Allows `--output-format json` for various uv commands.
- `package-conflicts`: Allows defining workspace conflicts at the package level.
- `pylock`: Allows installing from `pylock.toml` files.
- `python-install-default`: Allows
  [installing `python` and `python3` executables](./python-versions.md#installing-python-executables).
- `python-upgrade`: Allows
  [transparent Python version upgrades](./python-versions.md#upgrading-python-versions).
- `format`: Allows using `uv format`.
- `native-auth`: Enables storage of credentials in a
  [system-native location](../concepts/authentication/http.md#the-uv-credentials-store).

## Disabling preview features

The `--no-preview` option can be used to disable preview features.

    # Building distributions

To distribute your project to others (e.g., to upload it to an index like PyPI), you'll need to
build it into a distributable format.

Python projects are typically distributed as both source distributions (sdists) and binary
distributions (wheels). The former is typically a `.tar.gz` or `.zip` file containing the project's
source code along with some additional metadata, while the latter is a `.whl` file containing
pre-built artifacts that can be installed directly.

!!! important

    When using `uv build`, uv acts as a [build frontend](https://peps.python.org/pep-0517/#terminology-and-goals)
    and only determines the Python version to use and invokes the build backend. The details of
    the builds, such as the included files and the distribution filenames, are determined by the build
    backend, as defined in [`[build-system]`](./config.md#build-systems). Information about build
    configuration can be found in the respective tool's documentation.

## Using `uv build`

`uv build` can be used to build both source distributions and binary distributions for your project.
By default, `uv build` will build the project in the current directory, and place the built
artifacts in a `dist/` subdirectory:

```console
$ uv build
$ ls dist/
example-0.1.0-py3-none-any.whl
example-0.1.0.tar.gz
```

You can build the project in a different directory by providing a path to `uv build`, e.g.,
`uv build path/to/project`.

`uv build` will first build a source distribution, and then build a binary distribution (wheel) from
that source distribution.

You can limit `uv build` to building a source distribution with `uv build --sdist`, a binary
distribution with `uv build --wheel`, or build both distributions from source with
`uv build --sdist --wheel`.

## Build constraints

`uv build` accepts `--build-constraint`, which can be used to constrain the versions of any build
requirements during the build process. When coupled with `--require-hashes`, uv will enforce that
the requirement used to build the project match specific, known hashes, for reproducibility.

For example, given the following `constraints.txt`:

```text
setuptools==68.2.2 --hash=sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a
```

Running the following would build the project with the specified version of `setuptools`, and verify
that the downloaded `setuptools` distribution matches the specified hash:

```console
$ uv build --build-constraint constraints.txt --require-hashes
```

    # Configuring projects

## Python version requirement

Projects may declare the Python versions supported by the project in the `project.requires-python`
field of the `pyproject.toml`.

It is recommended to set a `requires-python` value:

```toml title="pyproject.toml" hl_lines="4"
[project]
name = "example"
version = "0.1.0"
requires-python = ">=3.12"
```

The Python version requirement determines the Python syntax that is allowed in the project and
affects selection of dependency versions (they must support the same Python version range).

## Entry points

[Entry points](https://packaging.python.org/en/latest/specifications/entry-points/#entry-points) are
the official term for an installed package to advertise interfaces. These include:

- [Command line interfaces](#command-line-interfaces)
- [Graphical user interfaces](#graphical-user-interfaces)
- [Plugin entry points](#plugin-entry-points)

!!! important

    Using the entry point tables requires a [build system](#build-systems) to be defined.

### Command-line interfaces

Projects may define command line interfaces (CLIs) for the project in the `[project.scripts]` table
of the `pyproject.toml`.

For example, to declare a command called `hello` that invokes the `hello` function in the `example`
module:

```toml title="pyproject.toml"
[project.scripts]
hello = "example:hello"
```

Then, the command can be run from a console:

```console
$ uv run hello
```

### Graphical user interfaces

Projects may define graphical user interfaces (GUIs) for the project in the `[project.gui-scripts]`
table of the `pyproject.toml`.

!!! important

    These are only different from [command-line interfaces](#command-line-interfaces) on Windows, where
    they are wrapped by a GUI executable so they can be started without a console. On other platforms,
    they behave the same.

For example, to declare a command called `hello` that invokes the `app` function in the `example`
module:

```toml title="pyproject.toml"
[project.gui-scripts]
hello = "example:app"
```

### Plugin entry points

Projects may define entry points for plugin discovery in the
[`[project.entry-points]`](https://packaging.python.org/en/latest/guides/creating-and-discovering-plugins/#using-package-metadata)
table of the `pyproject.toml`.

For example, to register the `example-plugin-a` package as a plugin for `example`:

```toml title="pyproject.toml"
[project.entry-points.'example.plugins']
a = "example_plugin_a"
```

Then, in `example`, plugins would be loaded with:

```python title="example/__init__.py"
from importlib.metadata import entry_points

for plugin in entry_points(group='example.plugins'):
    plugin.load()
```

!!! note

    The `group` key can be an arbitrary value, it does not need to include the package name or
    "plugins". However, it is recommended to namespace the key by the package name to avoid
    collisions with other packages.

## Build systems

A build system determines how the project should be packaged and installed. Projects may declare and
configure a build system in the `[build-system]` table of the `pyproject.toml`.

uv uses the presence of a build system to determine if a project contains a package that should be
installed in the project virtual environment. If a build system is not defined, uv will not attempt
to build or install the project itself, just its dependencies. If a build system is defined, uv will
build and install the project into the project environment.

The `--build-backend` option can be provided to `uv init` to create a packaged project with an
appropriate layout. The `--package` option can be provided to `uv init` to create a packaged project
with the default build system.

!!! note

    While uv will not build and install the current project without a build system definition,
    the presence of a `[build-system]` table is not required in other packages. For legacy reasons,
    if a build system is not defined, then `setuptools.build_meta:__legacy__` is used to build the
    package. Packages you depend on may not explicitly declare their build system but are still
    installable. Similarly, if you [add a dependency on a local project](./dependencies.md#path)
    or install it with `uv pip`, uv will attempt to build and install it regardless of the presence
    of a `[build-system]` table.

Build systems are used to power the following features:

- Including or excluding files from distributions
- Editable installation behavior
- Dynamic project metadata
- Compilation of native code
- Vendoring shared libraries

To configure these features, refer to the documentation of your chosen build system.

## Project packaging

As discussed in [build systems](#build-systems), a Python project must be built to be installed.
This process is generally referred to as "packaging".

You probably need a package if you want to:

- Add commands to the project
- Distribute the project to others
- Use a `src` and `test` layout
- Write a library

You probably _do not_ need a package if you are:

- Writing scripts
- Building a simple application
- Using a flat layout

While uv usually uses the declaration of a [build system](#build-systems) to determine if a project
should be packaged, uv also allows overriding this behavior with the
[`tool.uv.package`](../../reference/settings.md#package) setting.

Setting `tool.uv.package = true` will force a project to be built and installed into the project
environment. If no build system is defined, uv will use the setuptools legacy backend.

Setting `tool.uv.package = false` will force a project package _not_ to be built and installed into
the project environment. uv will ignore a declared build system when interacting with the project;
however, uv will still respect explicit attempts to build the project such as invoking `uv build`.

## Project environment path

The `UV_PROJECT_ENVIRONMENT` environment variable can be used to configure the project virtual
environment path (`.venv` by default).

If a relative path is provided, it will be resolved relative to the workspace root. If an absolute
path is provided, it will be used as-is, i.e., a child directory will not be created for the
environment. If an environment is not present at the provided path, uv will create it.

This option can be used to write to the system Python environment, though it is not recommended.
`uv sync` will remove extraneous packages from the environment by default and, as such, may leave
the system in a broken state.

To target the system environment, set `UV_PROJECT_ENVIRONMENT` to the prefix of the Python
installation. For example, on Debian-based systems, this is usually `/usr/local`:

```console
$ python -c "import sysconfig; print(sysconfig.get_config_var('prefix'))"
/usr/local
```

To target this environment, you'd export `UV_PROJECT_ENVIRONMENT=/usr/local`.

!!! important

    If an absolute path is provided and the setting is used across multiple projects, the
    environment will be overwritten by invocations in each project. This setting is only recommended
    for use for a single project in CI or Docker images.

!!! note

    By default, uv does not read the `VIRTUAL_ENV` environment variable during project operations.
    A warning will be displayed if `VIRTUAL_ENV` is set to a different path than the project's
    environment. The `--active` flag can be used to opt-in to respecting `VIRTUAL_ENV`. The
    `--no-active` flag can be used to silence the warning.

## Build isolation

By default, uv builds all packages in isolated virtual environments alongside their declared build
dependencies, as per [PEP 517](https://peps.python.org/pep-0517/).

Some packages are incompatible with this approach to build isolation, be it intentionally or
unintentionally.

For example, packages like [`flash-attn`](https://pypi.org/project/flash-attn/) and
[`deepspeed`](https://pypi.org/project/deepspeed/) need to build against the same version of PyTorch
that is installed in the project environment; by building them in an isolated environment, they may
inadvertently build against a different version of PyTorch, leading to runtime errors.

In other cases, packages may accidentally omit necessary dependencies in their declared build
dependency list. For example, [`cchardet`](https://pypi.org/project/cchardet/) requires `cython` to
be installed in the project environment prior to installing `cchardet`, but does not declare it as a
build dependency.

To address these issues, uv supports two separate approaches to modifying the build isolation
behavior:

1. **Augmenting the list of build dependencies**: This allows you to install a package in an
   isolated environment, but with additional build dependencies that are not declared by the package
   itself via the [`extra-build-dependencies`](../../reference/settings.md#extra-build-dependencies)
   setting. For packages like `flash-attn`, you can even enforce that those build dependencies (like
   `torch`) match the version of the package that is or will be installed in the project
   environment.

1. **Disabling build isolation for specific packages**: This allows you to install a package without
   building it in an isolated environment.

When possible, we recommend augmenting the build dependencies rather than disabling build isolation
entirely, as the latter approach requires that the build dependencies are installed in the project
environment _prior_ to installing the package itself, which can lead to more complex installation
steps, the inclusion of extraneous packages in the project environment, and difficulty in
reproducing the project environment in other contexts.

### Augmenting build dependencies

To augment the list of build dependencies for a specific package, add it to the
[`extra-build-dependencies`](../../reference/settings.md#extra-build-dependencies) list in your
`pyproject.toml`.

For example, to build `cchardet` with `cython` as an additional build dependency, include the
following in your `pyproject.toml`:

```toml title="pyproject.toml"
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["cchardet"]

[tool.uv.extra-build-dependencies]
cchardet = ["cython"]
```

To ensure that a build dependency matches the version of the package that is or will be installed in
the project environment, set `match-runtime = true` in the `extra-build-dependencies` table. For
example, to build `deepspeed` with `torch` as an additional build dependency, include the following
in your `pyproject.toml`:

```toml title="pyproject.toml"
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["deepspeed", "torch"]

[tool.uv.extra-build-dependencies]
deepspeed = [{ requirement = "torch", match-runtime = true }]
```

This will ensure that `deepspeed` is built with the same version of `torch` that is installed in the
project environment.

Similarly, to build `flash-attn` with `torch` as an additional build dependency, include the
following in your `pyproject.toml`:

```toml title="pyproject.toml"
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["flash-attn", "torch"]

[tool.uv.extra-build-dependencies]
flash-attn = [{ requirement = "torch", match-runtime = true }]

[tool.uv.extra-build-variables]
flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" }
```

!!! note

    The `FLASH_ATTENTION_SKIP_CUDA_BUILD` environment variable ensures that `flash-attn` is installed
    from a compatible, pre-built wheel, rather than attempting to build it from source, which requires
    access to the CUDA development toolkit. If the CUDA toolkit is not available, the environment variable
    can be omitted, and `flash-attn` will be installed from a pre-built wheel if one is available for the
    current platform, Python version, and PyTorch version.

Similarly, [`deep_gemm`](https://github.com/deepseek-ai/DeepGEMM) follows the same pattern:

```toml title="pyproject.toml"
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["deep_gemm", "torch"]

[tool.uv.sources]
deep_gemm = { git = "https://github.com/deepseek-ai/DeepGEMM" }

[tool.uv.extra-build-dependencies]
deep_gemm = [{ requirement = "torch", match-runtime = true }]
```

The use of `extra-build-dependencies` and `extra-build-variables` are tracked in the uv cache, such
that changes to these settings will trigger a reinstall and rebuild of the affected packages. For
example, in the case of `flash-attn`, upgrading the version of `torch` used in your project would
subsequently trigger a rebuild of `flash-attn` with the new version of `torch`.

#### Dynamic metadata

The use of `match-runtime = true` is only available for packages like `flash-attn` that declare
static metadata. If static metadata is unavailable, uv is required to build the package during the
dependency resolution phase; as such, uv cannot determine the version of the build dependency that
would ultimately be installed in the project environment.

In other words, if `flash-attn` did not declare static metadata, uv would not be able to determine
the version of `torch` that would be installed in the project environment, since it would need to
build `flash-attn` prior to resolving the `torch` version.

As a concrete example, [`axolotl`](https://pypi.org/project/axolotl/) is a popular package that
requires augmented build dependencies, but does not declare static metadata, as the package's
dependencies vary based on the version of `torch` that is installed in the project environment. In
this case, users should instead specify the exact version of `torch` that they intend to use in
their project, and then augment the build dependencies with that version.

For example, to build `axolotl` against `torch==2.6.0`, include the following in your
`pyproject.toml`:

```toml title="pyproject.toml"
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["axolotl[deepspeed, flash-attn]", "torch==2.6.0"]

[tool.uv.extra-build-dependencies]
axolotl = ["torch==2.6.0"]
deepspeed = ["torch==2.6.0"]
flash-attn = ["torch==2.6.0"]
```

Similarly, older versions of `flash-attn` did not declare static metadata, and thus would not have
supported `match-runtime = true` out of the box. Unlike `axolotl`, though, `flash-attn` did not vary
its dependencies based on dynamic properties of the build environment. As such, users could instead
provide the `flash-attn` metadata upfront via the
[`dependency-metadata`](../../reference/settings.md#dependency-metadata) setting, thereby forgoing
the need to build the package during the dependency resolution phase. For example, to provide the
`flash-attn` metadata upfront:

```toml title="pyproject.toml"
[[tool.uv.dependency-metadata]]
name = "flash-attn"
version = "2.6.3"
requires-dist = ["torch", "einops"]
```

!!! tip

    To determine the package metadata for a package like `flash-attn`, navigate to the appropriate Git repository,
    or look it up on [PyPI](https://pypi.org/project/flash-attn) and download the package's source distribution.
    The package requirements can typically be found in the `setup.py` or `setup.cfg` file.

    (If the package includes a built distribution, you can unzip it to find the `METADATA` file; however, the presence
    of a built distribution would negate the need to provide the metadata upfront, since it would already be available
    to uv.)

    The `version` field in `tool.uv.dependency-metadata` is optional for registry-based
    dependencies (when omitted, uv will assume the metadata applies to all versions of the package),
    but _required_ for direct URL dependencies (like Git dependencies).

### Disabling build isolation

Installing packages without build isolation requires that the package's build dependencies are
installed in the project environment _prior_ to building the package itself.

For example, historically, to install `cchardet` without build isolation, you would first need to
install the `cython` and `setuptools` packages in the project environment, followed by a separate
invocation to install `cchardet` without build isolation:

```console
$ uv venv
$ uv pip install cython setuptools
$ uv pip install cchardet --no-build-isolation
```

uv simplifies this process by allowing you to specify packages that should not be built in isolation
via the `no-build-isolation-package` setting in your `pyproject.toml` and the
`--no-build-isolation-package` flag in the command line. Further, when a package is marked for
disabling build isolation, uv will perform a two-phase install, first installing any packages that
support build isolation, followed by those that do not. As a result, if a project's build
dependencies are included as project dependencies, uv will automatically install them before
installing the package that requires build isolation to be disabled.

For example, to install `cchardet` without build isolation, include the following in your
`pyproject.toml`:

```toml title="pyproject.toml"
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["cchardet", "cython", "setuptools"]

[tool.uv]
no-build-isolation-package = ["cchardet"]
```

When running `uv sync`, uv will first install `cython` and `setuptools` in the project environment,
followed by `cchardet` (without build isolation):

```console
$ uv sync --extra build
 + cchardet==2.1.7
 + cython==3.1.3
 + setuptools==80.9.0
```

Similarly, to install `flash-attn` without build isolation, include the following in your
`pyproject.toml`:

```toml title="pyproject.toml"
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["flash-attn", "torch"]

[tool.uv]
no-build-isolation-package = ["flash-attn"]
```

When running `uv sync`, uv will first install `torch` in the project environment, followed by
`flash-attn` (without build isolation). As `torch` is both a project dependency and a build
dependency, the version of `torch` is guaranteed to be consistent between the build and runtime
environments.

A downside of the above approach is that it requires the build dependencies to be installed in the
project environment, which is appropriate for `flash-attn` (which requires `torch` both at
build-time and runtime), but not for `cchardet` (which only requires `cython` at build-time).

To avoid including build dependencies in the project environment, uv supports a two-step
installation process that allows you to separate the build dependencies from the packages that
require them.

For example, the build dependencies for `cchardet` can be isolated to an optional `build` group, as
in:

```toml title="pyproject.toml"
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["cchardet"]

[project.optional-dependencies]
build = ["setuptools", "cython"]

[tool.uv]
no-build-isolation-package = ["cchardet"]
```

Given the above, a user would first sync with the `build` optional group, and then without it to
remove the build dependencies:

```console
$ uv sync --extra build
 + cchardet==2.1.7
 + cython==3.1.3
 + setuptools==80.9.0
$ uv sync
 - cython==3.1.3
 - setuptools==80.9.0
```

Some packages, like `cchardet`, only require build dependencies for the _installation_ phase of
`uv sync`. Others require their build dependencies to be present even just to resolve the project's
dependencies during the _resolution_ phase.

In such cases, the build dependencies can be installed prior to running any `uv lock` or `uv sync`
commands, using the lower lower-level `uv pip` API. For example, given:

```toml title="pyproject.toml"
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["flash-attn"]

[tool.uv]
no-build-isolation-package = ["flash-attn"]
```

You could run the following sequence of commands to sync `flash-attn`:

```console
$ uv venv
$ uv pip install torch setuptools
$ uv sync
```

Alternatively, users can instead provide the `flash-attn` metadata upfront via the
[`dependency-metadata`](../../reference/settings.md#dependency-metadata) setting, thereby forgoing
the need to build the package during the dependency resolution phase. For example, to provide the
`flash-attn` metadata upfront:

```toml title="pyproject.toml"
[[tool.uv.dependency-metadata]]
name = "flash-attn"
version = "2.6.3"
requires-dist = ["torch", "einops"]
```

## Editable mode

By default, the project will be installed in editable mode, such that changes to the source code are
immediately reflected in the environment. `uv sync` and `uv run` both accept a `--no-editable` flag,
which instructs uv to install the project in non-editable mode. `--no-editable` is intended for
deployment use-cases, such as building a Docker container, in which the project should be included
in the deployed environment without a dependency on the originating source code.

## Conflicting dependencies

uv resolves all project dependencies together, including optional dependencies ("extras") and
dependency groups. If dependencies declared in one section are not compatible with those in another
section, uv will fail to resolve the requirements of the project with an error.

uv supports explicit declaration of conflicting dependency groups. For example, to declare that the
`optional-dependency` groups `extra1` and `extra2` are incompatible:

```toml title="pyproject.toml"
[tool.uv]
conflicts = [
    [
      { extra = "extra1" },
      { extra = "extra2" },
    ],
]
```

Or, to declare the development dependency groups `group1` and `group2` incompatible:

```toml title="pyproject.toml"
[tool.uv]
conflicts = [
    [
      { group = "group1" },
      { group = "group2" },
    ],
]
```

See the [resolution documentation](../resolution.md#conflicting-dependencies) for more.

## Limited resolution environments

If your project supports a more limited set of platforms or Python versions, you can constrain the
set of solved platforms via the `environments` setting, which accepts a list of PEP 508 environment
markers. For example, to constrain the lockfile to macOS and Linux, and exclude Windows:

```toml title="pyproject.toml"
[tool.uv]
environments = [
    "sys_platform == 'darwin'",
    "sys_platform == 'linux'",
]
```

See the [resolution documentation](../resolution.md#limited-resolution-environments) for more.

## Required environments

If your project _must_ support a specific platform or Python version, you can mark that platform as
required via the `required-environments` setting. For example, to require that the project supports
Intel macOS:

```toml title="pyproject.toml"
[tool.uv]
required-environments = [
    "sys_platform == 'darwin' and platform_machine == 'x86_64'",
]
```

The `required-environments` setting is only relevant for packages that do not publish a source
distribution (like PyTorch), as such packages can _only_ be installed on environments covered by the
set of pre-built binary distributions (wheels) published by that package.

See the [resolution documentation](../resolution.md#required-environments) for more.

    # Managing dependencies

## Dependency fields

Dependencies of the project are defined in several fields:

- [`project.dependencies`](#project-dependencies): Published dependencies.
- [`project.optional-dependencies`](#optional-dependencies): Published optional dependencies, or
  "extras".
- [`dependency-groups`](#dependency-groups): Local dependencies for development.
- [`tool.uv.sources`](#dependency-sources): Alternative sources for dependencies during development.

!!! 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:

```console
$ uv add httpx
```

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

```toml title="pyproject.toml" hl_lines="4"
[project]
name = "example"
version = "0.1.0"
dependencies = ["httpx>=0.27.2"]
```

The [`--dev`](#development-dependencies), [`--group`](#dependency-groups), or
[`--optional`](#optional-dependencies) 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`](../../reference/settings.md#add-bounds), or the constraint can be provided directly:

```console
$ 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:

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

The `pyproject.toml` will include a [Git source entry](#git):

```toml title="pyproject.toml" hl_lines="8-9"
[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.:

```console
$ 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 from requirements files

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

```
uv add -r requirements.txt
```

See the [pip migration guide](../../guides/migration/pip-to-project.md#importing-requirements-files)
for more details.

## Removing dependencies

To remove a dependency:

```console
$ uv remove httpx
```

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

If a [source](#dependency-sources) 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`:

```console
$ 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:

```console
$ 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](https://peps.python.org/pep-0508/#environment-markers).

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

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

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

```toml title="pyproject.toml" hl_lines="6"
[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:

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

See Python's [environment marker](https://peps.python.org/pep-0508/#environment-markers)
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](https://packaging.python.org/en/latest/specifications/dependency-specifiers/)
syntax, and the table follows the
[PEP 621](https://packaging.python.org/en/latest/specifications/pyproject-toml/) 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:

```toml title="pyproject.toml"
[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:

```toml title="pyproject.toml" hl_lines="7"
[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](#index): A package resolved from a specific package index.
- [Git](#git): A Git repository.
- [URL](#url): A remote wheel or source distribution.
- [Path](#path): A local wheel, source distribution, or project directory.
- [Workspace](#workspace-member): 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:

```console
$ 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:

```toml title="pyproject.toml"
[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.

```toml title="pyproject.toml" hl_lines="4"
[[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:

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

$ # Install over SSH.
$ uv add git+ssh://git@github.com/encode/httpx
```

```toml title="pyproject.toml" hl_lines="5"
[project]
dependencies = ["httpx"]

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

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

```console
$ uv add git+https://github.com/encode/httpx --tag 0.27.0
```

```toml title="pyproject.toml" hl_lines="7"
[project]
dependencies = ["httpx"]

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

Or, a branch:

```console
$ uv add git+https://github.com/encode/httpx --branch main
```

```toml title="pyproject.toml" hl_lines="7"
[project]
dependencies = ["httpx"]

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

Or, a revision (commit):

```console
$ uv add git+https://github.com/encode/httpx --rev 326b9431c761e1ef1e00b9f760d1f654c8db48c6
```

```toml title="pyproject.toml" hl_lines="7"
[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:

```console
$ uv add git+https://github.com/langchain-ai/langchain#subdirectory=libs/langchain
```

```toml title="pyproject.toml"
[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](../../concepts/resolution.md#source-distribution) for all supported formats).

For example:

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

Will result in a `pyproject.toml` with:

```toml title="pyproject.toml" hl_lines="5"
[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](../../concepts/resolution.md#source-distribution) for all supported formats), or a directory
containing a `pyproject.toml`.

For example:

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

Will result in a `pyproject.toml` with:

```toml title="pyproject.toml"
[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:

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

Or, a path to a project directory:

```console
$ uv add ~/projects/bar/
```

!!! important

    When using a directory as a path dependency, uv will attempt to build and install the target as
    a package by default. See the [virtual dependency](#virtual-dependencies) documentation for
    details.

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 }
```

!!! tip

    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](#editable-dependencies) . See the [workspace](./workspaces.md) documentation for more
details on workspaces.

```toml title="pyproject.toml"
[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](https://packaging.python.org/en/latest/specifications/dependency-specifiers/)-compatible
environment markers for the source.

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

```toml title="pyproject.toml" hl_lines="8"
[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](https://peps.python.org/pep-0508/#environment-markers)-compatible
environment markers.

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

```toml title="pyproject.toml" hl_lines="6-7"
[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:

```toml title="pyproject.toml" hl_lines="6-7"
[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:

```console
$ uv lock --no-sources
```

The use of `--no-sources` will also prevent uv from discovering any
[workspace members](#workspace-member) 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](https://pandas.pydata.org/docs/getting_started/install.html#excel-files) and a
[`plot` extra](https://pandas.pydata.org/docs/getting_started/install.html#visualization) 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](#dependency-specifiers)
syntax.

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

```toml title="pyproject.toml"
[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:

```console
$ 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:

```toml title="pyproject.toml"
[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:

```console
$ uv add --dev pytest
```

uv uses the `[dependency-groups]` table (as defined in [PEP 735](https://peps.python.org/pep-0735/))
for declaration of development dependencies. The above command will create a `dev` group:

```toml title="pyproject.toml"
[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](#default-groups).

### 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:

```console
$ uv add --group lint ruff
```

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

```toml title="pyproject.toml"
[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).

### Nesting groups

A dependency group can include other dependency groups, e.g.:

```toml title="pyproject.toml"
[dependency-groups]
dev = [
  {include-group = "lint"},
  {include-group = "test"}
]
lint = [
  "ruff"
]
test = [
  "pytest"
]
```

An included group's dependencies cannot conflict with the other dependencies declared in a group.

### 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.

```toml title="pyproject.toml"
[tool.uv]
default-groups = ["dev", "foo"]
```

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

```toml title="pyproject.toml"
[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>`.

### Group `requires-python`

By default, dependency groups must be compatible with your project's `requires-python` range.

If a dependency group requires a different range of Python versions than your project, you can
specify a `requires-python` for the group in `[tool.uv.dependency-groups]`, e.g.:

```toml title="pyproject.toml" hl_lines="9-10"
[project]
name = "example"
version = "0.0.0"
requires-python = ">=3.10"

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

[tool.uv.dependency-groups]
dev = {requires-python = ">=3.12"}
```

### Legacy `dev-dependencies`

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

```toml title="pyproject.toml"
[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](./config.md#build-systems), 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](https://peps.python.org/pep-0518/).

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

```toml title="pyproject.toml"
[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`:

```toml title="pyproject.toml"
[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`](https://github.com/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:

```console
$ uv add --editable ./path/foo
```

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

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

## Virtual dependencies

uv allows dependencies to be "virtual", in which the dependency itself is not installed as a
[package](./config.md#project-packaging), but its dependencies are.

By default, dependencies are never virtual.

A dependency with a [`path` source](#path) can be virtual if it explicitly sets
[`tool.uv.package = false`](../../reference/settings.md#package). Unlike working _in_ the dependent
project with uv, the package will be built even if a [build system](./config.md#build-systems) is
not declared.

To treat a dependency as virtual, set `package = false` on the source:

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

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

If a dependency sets `tool.uv.package = false`, it can be overridden by declaring `package = true`
on the source:

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

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

Similarly, a dependency with a [`workspace` source](#workspace-member) can be virtual if it
explicitly sets [`tool.uv.package = false`](../../reference/settings.md#package). The workspace
member will be built even if a [build system](./config.md#build-systems) is not declared.

Workspace members that are _not_ dependencies can be virtual by default, e.g., if the parent
`pyproject.toml` is:

```toml title="pyproject.toml"
[project]
name = "parent"
version = "1.0.0"
dependencies = []

[tool.uv.workspace]
members = ["child"]
```

And the child `pyproject.toml` excluded a build system:

```toml title="pyproject.toml"
[project]
name = "child"
version = "1.0.0"
dependencies = ["anyio"]
```

Then the `child` workspace member would not be installed, but the transitive dependency `anyio`
would be.

In contrast, if the parent declared a dependency on `child`:

```toml title="pyproject.toml"
[project]
name = "parent"
version = "1.0.0"
dependencies = ["child"]

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

[tool.uv.workspace]
members = ["child"]
```

Then `child` would be built and installed.

## Dependency specifiers

uv uses standard
[dependency specifiers](https://packaging.python.org/en/latest/specifications/dependency-specifiers/),
originally defined in [PEP 508](https://peps.python.org/pep-0508/). 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.

    # Projects

Projects help manage Python code spanning multiple files.

!!! tip

    Looking for an introduction to creating a project with uv? See the [projects guide](../../guides/projects.md) first.

Working on projects is a core part of the uv experience. Learn more about using projects:

- [Understanding project structure and files](./layout.md)
- [Creating new projects](./init.md)
- [Managing project dependencies](./dependencies.md)
- [Running commands and scripts in a project](./run.md)
- [Using lockfiles and syncing the environment](./sync.md)
- [Configuring the project for advanced use cases](./config.md)
- [Building distributions to publish a project](./build.md)
- [Using workspaces to work on multiple projects at once](./workspaces.md)

    # Creating projects

uv supports creating a project with `uv init`.

When creating projects, uv supports two basic templates: [**applications**](#applications) and
[**libraries**](#libraries). By default, uv will create a project for an application. The `--lib`
flag can be used to create a project for a library instead.

## Target directory

uv will create a project in the working directory, or, in a target directory by providing a name,
e.g., `uv init foo`. If there's already a project in the target directory, i.e., if there's a
`pyproject.toml`, uv will exit with an error.

## Applications

Application projects are suitable for web servers, scripts, and command-line interfaces.

Applications are the default target for `uv init`, but can also be specified with the `--app` flag.

```console
$ uv init example-app
```

The project includes a `pyproject.toml`, a sample file (`main.py`), a readme, and a Python version
pin file (`.python-version`).

```console
$ tree example-app
example-app
├── .python-version
├── README.md
├── main.py
└── pyproject.toml
```

!!! note

    Prior to v0.6.0, uv created a file named `hello.py` instead of `main.py`.

The `pyproject.toml` includes basic metadata. It does not include a build system, it is not a
[package](./config.md#project-packaging) and will not be installed into the environment:

```toml title="pyproject.toml"
[project]
name = "example-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
```

The sample file defines a `main` function with some standard boilerplate:

```python title="main.py"
def main():
    print("Hello from example-app!")


if __name__ == "__main__":
    main()
```

Python files can be executed with `uv run`:

```console
$ cd example-app
$ uv run main.py
Hello from example-project!
```

## Packaged applications

Many use-cases require a [package](./config.md#project-packaging). For example, if you are creating
a command-line interface that will be published to PyPI or if you want to define tests in a
dedicated directory.

The `--package` flag can be used to create a packaged application:

```console
$ uv init --package example-pkg
```

The source code is moved into a `src` directory with a module directory and an `__init__.py` file:

```console
$ tree example-pkg
example-pkg
├── .python-version
├── README.md
├── pyproject.toml
└── src
    └── example_pkg
        └── __init__.py
```

A [build system](./config.md#build-systems) is defined, so the project will be installed into the
environment:

```toml title="pyproject.toml" hl_lines="12-14"
[project]
name = "example-pkg"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[project.scripts]
example-pkg = "example_pkg:main"

[build-system]
requires = ["uv_build>=0.8.22,<0.9.0"]
build-backend = "uv_build"
```

!!! tip

    The `--build-backend` option can be used to request an alternative build system.

A [command](./config.md#entry-points) definition is included:

```toml title="pyproject.toml" hl_lines="9 10"
[project]
name = "example-pkg"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[project.scripts]
example-pkg = "example_pkg:main"

[build-system]
requires = ["uv_build>=0.8.22,<0.9.0"]
build-backend = "uv_build"
```

The command can be executed with `uv run`:

```console
$ cd example-pkg
$ uv run example-pkg
Hello from example-pkg!
```

## Libraries

A library provides functions and objects for other projects to consume. Libraries are intended to be
built and distributed, e.g., by uploading them to PyPI.

Libraries can be created by using the `--lib` flag:

```console
$ uv init --lib example-lib
```

!!! note

    Using `--lib` implies `--package`. Libraries always require a packaged project.

As with a [packaged application](#packaged-applications), a `src` layout is used. A `py.typed`
marker is included to indicate to consumers that types can be read from the library:

```console
$ tree example-lib
example-lib
├── .python-version
├── README.md
├── pyproject.toml
└── src
    └── example_lib
        ├── py.typed
        └── __init__.py
```

!!! note

    A `src` layout is particularly valuable when developing libraries. It ensures that the library is
    isolated from any `python` invocations in the project root and that distributed library code is
    well separated from the rest of the project source.

A [build system](./config.md#build-systems) is defined, so the project will be installed into the
environment:

```toml title="pyproject.toml" hl_lines="12-14"
[project]
name = "example-lib"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[build-system]
requires = ["uv_build>=0.8.22,<0.9.0"]
build-backend = "uv_build"
```

!!! tip

    You can select a different build backend template by using `--build-backend` with `hatchling`,
    `uv_build`, `flit-core`, `pdm-backend`, `setuptools`, `maturin`, or `scikit-build-core`. An
    alternative backend is required if you want to create a [library with extension modules](#projects-with-extension-modules).

The created module defines a simple API function:

```python title="__init__.py"
def hello() -> str:
    return "Hello from example-lib!"
```

And you can import and execute it using `uv run`:

```console
$ cd example-lib
$ uv run python -c "import example_lib; print(example_lib.hello())"
Hello from example-lib!
```

## Projects with extension modules

Most Python projects are "pure Python", meaning they do not define modules in other languages like
C, C++, FORTRAN, or Rust. However, projects with extension modules are often used for performance
sensitive code.

Creating a project with an extension module requires choosing an alternative build system. uv
supports creating projects with the following build systems that support building extension modules:

- [`maturin`](https://www.maturin.rs) for projects with Rust
- [`scikit-build-core`](https://github.com/scikit-build/scikit-build-core) for projects with C, C++,
  FORTRAN, Cython

Specify the build system with the `--build-backend` flag:

```console
$ uv init --build-backend maturin example-ext
```

!!! note

    Using `--build-backend` implies `--package`.

The project contains a `Cargo.toml` and a `lib.rs` file in addition to the typical Python project
files:

```console
$ tree example-ext
example-ext
├── .python-version
├── Cargo.toml
├── README.md
├── pyproject.toml
└── src
    ├── lib.rs
    └── example_ext
        ├── __init__.py
        └── _core.pyi
```

!!! note

    If using `scikit-build-core`, you'll see CMake configuration and a `main.cpp` file instead.

The Rust library defines a simple function:

```rust title="src/lib.rs"
use pyo3::prelude::*;

#[pyfunction]
fn hello_from_bin() -> String {
    "Hello from example-ext!".to_string()
}

#[pymodule]
fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(hello_from_bin, m)?)?;
    Ok(())
}
```

And the Python module imports it:

```python title="src/example_ext/__init__.py"
from example_ext._core import hello_from_bin


def main() -> None:
    print(hello_from_bin())
```

The command can be executed with `uv run`:

```console
$ cd example-ext
$ uv run example-ext
Hello from example-ext!
```

!!! important

    When creating a project with maturin or scikit-build-core, uv configures [`tool.uv.cache-keys`](https://docs.astral.sh/uv/reference/settings/#cache-keys)
    to include common source file types. To force a rebuild, e.g. when changing files outside
    `cache-keys` or when not using `cache-keys`, use `--reinstall`.

## Creating a minimal project

If you only want to create a `pyproject.toml`, use the `--bare` option:

```console
$ uv init example --bare
```

uv will skip creating a Python version pin file, a README, and any source directories or files.
Additionally, uv will not initialize a version control system (i.e., `git`).

```console
$ tree example-bare
example-bare
└── pyproject.toml
```

uv will also not add extra metadata to the `pyproject.toml`, such as the `description` or `authors`.

```toml
[project]
name = "example"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
```

The `--bare` option can be used with other options like `--lib` or `--build-backend` — in these
cases uv will still configure a build system but will not create the expected file structure.

When `--bare` is used, additional features can still be used opt-in:

```console
$ uv init example --bare --description "Hello world" --author-from git --vcs git --python-pin
```

    # Project structure and files

## The `pyproject.toml`

Python project metadata is defined in a
[`pyproject.toml`](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/) file. uv
requires this file to identify the root directory of a project.

!!! tip

    `uv init` can be used to create a new project. See [Creating projects](./init.md) for
    details.

A minimal project definition includes a name and version:

```toml title="pyproject.toml"
[project]
name = "example"
version = "0.1.0"
```

Additional project metadata and configuration includes:

- [Python version requirement](./config.md#python-version-requirement)
- [Dependencies](./dependencies.md)
- [Build system](./config.md#build-systems)
- [Entry points (commands)](./config.md#entry-points)

## The project environment

When working on a project with uv, uv will create a virtual environment as needed. While some uv
commands will create a temporary environment (e.g., `uv run --isolated`), uv also manages a
persistent environment with the project and its dependencies in a `.venv` directory next to the
`pyproject.toml`. It is stored inside the project to make it easy for editors to find — they need
the environment to give code completions and type hints. It is not recommended to include the
`.venv` directory in version control; it is automatically excluded from `git` with an internal
`.gitignore` file.

To run a command in the project environment, use `uv run`. Alternatively the project environment can
be activated as normal for a virtual environment.

When `uv run` is invoked, it will create the project environment if it does not exist yet or ensure
it is up-to-date if it exists. The project environment can also be explicitly created with
`uv sync`. See the [locking and syncing](./sync.md) documentation for details.

It is _not_ recommended to modify the project environment manually, e.g., with `uv pip install`. For
project dependencies, use `uv add` to add a package to the environment. For one-off requirements,
use [`uvx`](../../guides/tools.md) or
[`uv run --with`](./run.md#requesting-additional-dependencies).

!!! tip

    If you don't want uv to manage the project environment, set [`managed = false`](../../reference/settings.md#managed)
    to disable automatic locking and syncing of the project. For example:

    ```toml title="pyproject.toml"
    [tool.uv]
    managed = false
    ```

## The lockfile

uv creates a `uv.lock` file next to the `pyproject.toml`.

`uv.lock` is a _universal_ or _cross-platform_ lockfile that captures the packages that would be
installed across all possible Python markers such as operating system, architecture, and Python
version.

Unlike the `pyproject.toml`, which is used to specify the broad requirements of your project, the
lockfile contains the exact resolved versions that are installed in the project environment. This
file should be checked into version control, allowing for consistent and reproducible installations
across machines.

A lockfile ensures that developers working on the project are using a consistent set of package
versions. Additionally, it ensures when deploying the project as an application that the exact set
of used package versions is known.

The lockfile is [automatically created and updated](./sync.md#automatic-lock-and-sync) during uv
invocations that use the project environment, i.e., `uv sync` and `uv run`. The lockfile may also be
explicitly updated using `uv lock`.

`uv.lock` is a human-readable TOML file but is managed by uv and should not be edited manually. The
`uv.lock` format is specific to uv and not usable by other tools.

### Relationship to `pylock.toml`

In [PEP 751](https://peps.python.org/pep-0751/), Python standardized a new resolution file format,
`pylock.toml`.

`pylock.toml` is a resolution output format intended to replace `requirements.txt` (e.g., in the
context of `uv pip compile`, whereby a "locked" `requirements.txt` file is generated from a set of
input requirements). `pylock.toml` is standardized and tool-agnostic, such that in the future,
`pylock.toml` files generated by uv could be installed by other tools, and vice versa.

Some of uv's functionality cannot be expressed in the `pylock.toml` format; as such, uv will
continue to use the `uv.lock` format within the project interface.

However, uv supports `pylock.toml` as an export target and in the `uv pip` CLI. For example:

- To export a `uv.lock` to the `pylock.toml` format, run: `uv export -o pylock.toml`
- To generate a `pylock.toml` file from a set of requirements, run:
  `uv pip compile -o pylock.toml -r requirements.in`
- To install from a `pylock.toml` file, run: `uv pip sync pylock.toml` or
  `uv pip install -r pylock.toml`

    # Running commands in projects

When working on a project, it is installed into the virtual environment at `.venv`. This environment
is isolated from the current shell by default, so invocations that require the project, e.g.,
`python -c "import example"`, will fail. Instead, use `uv run` to run commands in the project
environment:

```console
$ uv run python -c "import example"
```

When using `run`, uv will ensure that the project environment is up-to-date before running the given
command.

The given command can be provided by the project environment or exist outside of it, e.g.:

```console
$ # Presuming the project provides `example-cli`
$ uv run example-cli foo

$ # Running a `bash` script that requires the project to be available
$ uv run bash scripts/foo.sh
```

## Requesting additional dependencies

Additional dependencies or different versions of dependencies can be requested per invocation.

The `--with` option is used to include a dependency for the invocation, e.g., to request a different
version of `httpx`:

```console
$ uv run --with httpx==0.26.0 python -c "import httpx; print(httpx.__version__)"
0.26.0
$ uv run --with httpx==0.25.0 python -c "import httpx; print(httpx.__version__)"
0.25.0
```

The requested version will be respected regardless of the project's requirements. For example, even
if the project requires `httpx==0.24.0`, the output above would be the same.

## Running scripts

Scripts that declare inline metadata are automatically executed in environments isolated from the
project. See the [scripts guide](../../guides/scripts.md#declaring-script-dependencies) for more
details.

For example, given a script:

```python title="example.py"
# /// script
# dependencies = [
#   "httpx",
# ]
# ///

import httpx

resp = httpx.get("https://peps.python.org/api/peps.json")
data = resp.json()
print([(k, v["title"]) for k, v in data.items()][:10])
```

The invocation `uv run example.py` would run _isolated_ from the project with only the given
dependencies listed.

## Legacy scripts on Windows

Support is provided for
[legacy setuptools scripts](https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#scripts).
These types of scripts are additional files installed by setuptools in `.venv\Scripts`.

Currently only legacy scripts with the `.ps1`, `.cmd`, and `.bat` extensions are supported.

For example, below is an example running a Command Prompt script.

```console
$ uv run --with nuitka==2.6.7 -- nuitka.cmd --version
```

In addition, you don't need to specify the extension. `uv` will automatically look for files ending
in `.ps1`, `.cmd`, and `.bat` in that order of execution on your behalf.

```console
$ uv run --with nuitka==2.6.7 -- nuitka --version
```

## Signal handling

uv does not cede control of the process to the spawned command in order to provide better error
messages on failure. Consequently, uv is responsible for forwarding some signals to the child
process the requested command runs in.

On Unix systems, uv will forward SIGINT and SIGTERM to the child process. Since terminals send
SIGINT to the foreground process group on Ctrl-C, uv will only forward a SIGINT to the child process
if it is sent more than once or the child process group differs from uv's.

On Windows, these concepts do not apply and uv ignores Ctrl-C events, deferring handling to the
child process so it can exit cleanly.

    # Locking and syncing

Locking is the process of resolving your project's dependencies into a
[lockfile](./layout.md#the-lockfile). Syncing is the process of installing a subset of packages from
the lockfile into the [project environment](./layout.md#the-project-environment).

## Automatic lock and sync

Locking and syncing are _automatic_ in uv. For example, when `uv run` is used, the project is locked
and synced before invoking the requested command. This ensures the project environment is always
up-to-date. Similarly, commands which read the lockfile, such as `uv tree`, will automatically
update it before running.

To disable automatic locking, use the `--locked` option:

```console
$ uv run --locked ...
```

If the lockfile is not up-to-date, uv will raise an error instead of updating the lockfile.

To use the lockfile without checking if it is up-to-date, use the `--frozen` option:

```console
$ uv run --frozen ...
```

Similarly, to run a command without checking if the environment is up-to-date, use the `--no-sync`
option:

```console
$ uv run --no-sync ...
```

## Checking the lockfile

When considering if the lockfile is up-to-date, uv will check if it matches the project metadata.
For example, if you add a dependency to your `pyproject.toml`, the lockfile will be considered
outdated. Similarly, if you change the version constraints for a dependency such that the locked
version is excluded, the lockfile will be considered outdated. However, if you change the version
constraints such that the existing locked version is still included, the lockfile will still be
considered up-to-date.

You can check if the lockfile is up-to-date by passing the `--check` flag to `uv lock`:

```console
$ uv lock --check
```

This is equivalent to the `--locked` flag for other commands.

!!! important

    uv will not consider lockfiles outdated when new versions of packages are released — the lockfile
    needs to be explicitly updated if you want to upgrade dependencies. See the documentation on
    [upgrading locked package versions](#upgrading-locked-package-versions) for details.

## Creating the lockfile

While the lockfile is created [automatically](#automatic-lock-and-sync), the lockfile may also be
explicitly created or updated using `uv lock`:

```console
$ uv lock
```

## Syncing the environment

While the environment is synced [automatically](#automatic-lock-and-sync), it may also be explicitly
synced using `uv sync`:

```console
$ uv sync
```

Syncing the environment manually is especially useful for ensuring your editor has the correct
versions of dependencies.

### Editable installation

When the environment is synced, uv will install the project (and other workspace members) as
_editable_ packages, such that re-syncing is not necessary for changes to be reflected in the
environment.

To opt-out of this behavior, use the `--no-editable` option.

!!! note

    If the project does not define a build system, it will not be installed.
    See the [build systems](./config.md#build-systems) documentation for details.

### Retaining extraneous packages

Syncing is "exact" by default, which means it will remove any packages that are not present in the
lockfile.

To retain extraneous packages, use the `--inexact` option:

```console
$ uv sync --inexact
```

### Syncing optional dependencies

uv reads optional dependencies from the `[project.optional-dependencies]` table. These are
frequently referred to as "extras".

uv does not sync extras by default. Use the `--extra` option to include an extra.

```console
$ uv sync --extra foo
```

To quickly enable all extras, use the `--all-extras` option.

See the [optional dependencies](./dependencies.md#optional-dependencies) documentation for details
on how to manage optional dependencies.

### Syncing development dependencies

uv reads development dependencies from the `[dependency-groups]` table (as defined in
[PEP 735](https://peps.python.org/pep-0735/)).

The `dev` group is special-cased and synced by default. See the
[default groups](./dependencies.md#default-groups) documentation for details on changing the
defaults.

The `--no-dev` flag can be used to exclude the `dev` group.

The `--only-dev` flag can be used to install the `dev` group _without_ the project and its
dependencies.

Additional groups can be included or excluded with the `--all-groups`, `--no-default-groups`,
`--group <name>`, `--only-group <name>`, and `--no-group <name>` options. The semantics of
`--only-group` are the same as `--only-dev`, the project will not be included. However,
`--only-group` will also exclude default groups.

Group exclusions always take precedence over inclusions, so given the command:

```
$ uv sync --no-group foo --group foo
```

The `foo` group would not be installed.

See the [development dependencies](./dependencies.md#development-dependencies) documentation for
details on how to manage development dependencies.

## Upgrading locked package versions

With an existing `uv.lock` file, uv will prefer the previously locked versions of packages when
running `uv sync` and `uv lock`. Package versions will only change if the project's dependency
constraints exclude the previous, locked version.

To upgrade all packages:

```console
$ uv lock --upgrade
```

To upgrade a single package to the latest version, while retaining the locked versions of all other
packages:

```console
$ uv lock --upgrade-package <package>
```

To upgrade a single package to a specific version:

```console
$ uv lock --upgrade-package <package>==<version>
```

In all cases, upgrades are limited to the project's dependency constraints. For example, if the
project defines an upper bound for a package then an upgrade will not go beyond that version.

!!! note

    uv applies similar logic to Git dependencies. For example, if a Git dependency references
    the `main` branch, uv will prefer the locked commit SHA in an existing `uv.lock` file over
    the latest commit on the `main` branch, unless the `--upgrade` or `--upgrade-package` flags
    are used.

These flags can also be provided to `uv sync` or `uv run` to update the lockfile _and_ the
environment.

## Exporting the lockfile

If you need to integrate uv with other tools or workflows, you can export `uv.lock` to the
`requirements.txt` format with `uv export --format requirements-txt`. The generated
`requirements.txt` file can then be installed via `uv pip install`, or with other tools like `pip`.

In general, we recommend against using both a `uv.lock` and a `requirements.txt` file. If you find
yourself exporting a `uv.lock` file, consider opening an issue to discuss your use case.

## Partial installations

Sometimes it's helpful to perform installations in multiple steps, e.g., for optimal layer caching
while building a Docker image. `uv sync` has several flags for this purpose.

- `--no-install-project`: Do not install the current project
- `--no-install-workspace`: Do not install any workspace members, including the root project
- `--no-install-package <NO_INSTALL_PACKAGE>`: Do not install the given package(s)

When these options are used, all the dependencies of the target are still installed. For example,
`--no-install-project` will omit the _project_ but not any of its dependencies.

If used improperly, these flags can result in a broken environment since a package can be missing
its dependencies.

    # Using workspaces

Inspired by the [Cargo](https://doc.rust-lang.org/cargo/reference/workspaces.html) concept of the
same name, a workspace is "a collection of one or more packages, called _workspace members_, that
are managed together."

Workspaces organize large codebases by splitting them into multiple packages with common
dependencies. Think: a FastAPI-based web application, alongside a series of libraries that are
versioned and maintained as separate Python packages, all in the same Git repository.

In a workspace, each package defines its own `pyproject.toml`, but the workspace shares a single
lockfile, ensuring that the workspace operates with a consistent set of dependencies.

As such, `uv lock` operates on the entire workspace at once, while `uv run` and `uv sync` operate on
the workspace root by default, though both accept a `--package` argument, allowing you to run a
command in a particular workspace member from any workspace directory.

## Getting started

To create a workspace, add a `tool.uv.workspace` table to a `pyproject.toml`, which will implicitly
create a workspace rooted at that package.

!!! tip

    By default, running `uv init` inside an existing package will add the newly created member to the workspace, creating a `tool.uv.workspace` table in the workspace root if it doesn't already exist.

In defining a workspace, you must specify the `members` (required) and `exclude` (optional) keys,
which direct the workspace to include or exclude specific directories as members respectively, and
accept lists of globs:

```toml title="pyproject.toml"
[project]
name = "albatross"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["bird-feeder", "tqdm>=4,<5"]

[tool.uv.sources]
bird-feeder = { workspace = true }

[tool.uv.workspace]
members = ["packages/*"]
exclude = ["packages/seeds"]
```

Every directory included by the `members` globs (and not excluded by the `exclude` globs) must
contain a `pyproject.toml` file. However, workspace members can be _either_
[applications](./init.md#applications) or [libraries](./init.md#libraries); both are supported in
the workspace context.

Every workspace needs a root, which is _also_ a workspace member. In the above example, `albatross`
is the workspace root, and the workspace members include all projects under the `packages`
directory, except `seeds`.

By default, `uv run` and `uv sync` operates on the workspace root. For example, in the above
example, `uv run` and `uv run --package albatross` would be equivalent, while
`uv run --package bird-feeder` would run the command in the `bird-feeder` package.

## Workspace sources

Within a workspace, dependencies on workspace members are facilitated via
[`tool.uv.sources`](./dependencies.md), as in:

```toml title="pyproject.toml"
[project]
name = "albatross"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["bird-feeder", "tqdm>=4,<5"]

[tool.uv.sources]
bird-feeder = { workspace = true }

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

[build-system]
requires = ["uv_build>=0.8.22,<0.9.0"]
build-backend = "uv_build"
```

In this example, the `albatross` project depends on the `bird-feeder` project, which is a member of
the workspace. The `workspace = true` key-value pair in the `tool.uv.sources` table indicates the
`bird-feeder` dependency should be provided by the workspace, rather than fetched from PyPI or
another registry.

!!! note

    Dependencies between workspace members are editable.

Any `tool.uv.sources` definitions in the workspace root apply to all members, unless overridden in
the `tool.uv.sources` of a specific member. For example, given the following `pyproject.toml`:

```toml title="pyproject.toml"
[project]
name = "albatross"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["bird-feeder", "tqdm>=4,<5"]

[tool.uv.sources]
bird-feeder = { workspace = true }
tqdm = { git = "https://github.com/tqdm/tqdm" }

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

[build-system]
requires = ["uv_build>=0.8.22,<0.9.0"]
build-backend = "uv_build"
```

Every workspace member would, by default, install `tqdm` from GitHub, unless a specific member
overrides the `tqdm` entry in its own `tool.uv.sources` table.

!!! note

    If a workspace member provides `tool.uv.sources` for some dependency, it will ignore any
    `tool.uv.sources` for the same dependency in the workspace root, even if the member's source is
    limited by a [marker](dependencies.md#platform-specific-sources) that doesn't match the current
    platform.

## Workspace layouts

The most common workspace layout can be thought of as a root project with a series of accompanying
libraries.

For example, continuing with the above example, this workspace has an explicit root at `albatross`,
with two libraries (`bird-feeder` and `seeds`) in the `packages` directory:

```text
albatross
├── packages
│   ├── bird-feeder
│   │   ├── pyproject.toml
│   │   └── src
│   │       └── bird_feeder
│   │           ├── __init__.py
│   │           └── foo.py
│   └── seeds
│       ├── pyproject.toml
│       └── src
│           └── seeds
│               ├── __init__.py
│               └── bar.py
├── pyproject.toml
├── README.md
├── uv.lock
└── src
    └── albatross
        └── main.py
```

Since `seeds` was excluded in the `pyproject.toml`, the workspace has two members total: `albatross`
(the root) and `bird-feeder`.

## When (not) to use workspaces

Workspaces are intended to facilitate the development of multiple interconnected packages within a
single repository. As a codebase grows in complexity, it can be helpful to split it into smaller,
composable packages, each with their own dependencies and version constraints.

Workspaces help enforce isolation and separation of concerns. For example, in uv, we have separate
packages for the core library and the command-line interface, enabling us to test the core library
independently of the CLI, and vice versa.

Other common use cases for workspaces include:

- A library with a performance-critical subroutine implemented in an extension module (Rust, C++,
  etc.).
- A library with a plugin system, where each plugin is a separate workspace package with a
  dependency on the root.

Workspaces are _not_ suited for cases in which members have conflicting requirements, or desire a
separate virtual environment for each member. In this case, path dependencies are often preferable.
For example, rather than grouping `albatross` and its members in a workspace, you can always define
each package as its own independent project, with inter-package dependencies defined as path
dependencies in `tool.uv.sources`:

```toml title="pyproject.toml"
[project]
name = "albatross"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["bird-feeder", "tqdm>=4,<5"]

[tool.uv.sources]
bird-feeder = { path = "packages/bird-feeder" }

[build-system]
requires = ["uv_build>=0.8.22,<0.9.0"]
build-backend = "uv_build"
```

This approach conveys many of the same benefits, but allows for more fine-grained control over
dependency resolution and virtual environment management (with the downside that `uv run --package`
is no longer available; instead, commands must be run from the relevant package directory).

Finally, uv's workspaces enforce a single `requires-python` for the entire workspace, taking the
intersection of all members' `requires-python` values. If you need to support testing a given member
on a Python version that isn't supported by the rest of the workspace, you may need to use `uv pip`
to install that member in a separate virtual environment.

!!! note

    As Python does not provide dependency isolation, uv can't ensure that a package uses its declared dependencies and nothing else. For workspaces specifically, uv can't ensure that packages don't import dependencies declared by another workspace member.

    # Python versions

A Python version is composed of a Python interpreter (i.e. the `python` executable), the standard
library, and other supporting files.

## Managed and system Python installations

Since it is common for a system to have an existing Python installation, uv supports
[discovering](#discovery-of-python-versions) Python versions. However, uv also supports
[installing Python versions](#installing-a-python-version) itself. To distinguish between these two
types of Python installations, uv refers to Python versions it installs as _managed_ Python
installations and all other Python installations as _system_ Python installations.

!!! note

    uv does not distinguish between Python versions installed by the operating system vs those
    installed and managed by other tools. For example, if a Python installation is managed with
    `pyenv`, it would still be considered a _system_ Python version in uv.

## Requesting a version

A specific Python version can be requested with the `--python` flag in most uv commands. For
example, when creating a virtual environment:

```console
$ uv venv --python 3.11.6
```

uv will ensure that Python 3.11.6 is available — downloading and installing it if necessary — then
create the virtual environment with it.

The following Python version request formats are supported:

- `<version>` (e.g., `3`, `3.12`, `3.12.3`)
- `<version-specifier>` (e.g., `>=3.12,<3.13`)
- `<version><short-variant>` (e.g., `3.13t`, `3.12.0d`)
- `<version>+<variant>` (e.g., `3.13+freethreaded`, `3.12.0+debug`)
- `<implementation>` (e.g., `cpython` or `cp`)
- `<implementation>@<version>` (e.g., `cpython@3.12`)
- `<implementation><version>` (e.g., `cpython3.12` or `cp312`)
- `<implementation><version-specifier>` (e.g., `cpython>=3.12,<3.13`)
- `<implementation>-<version>-<os>-<arch>-<libc>` (e.g., `cpython-3.12.3-macos-aarch64-none`)

Additionally, a specific system Python interpreter can be requested with:

- `<executable-path>` (e.g., `/opt/homebrew/bin/python3`)
- `<executable-name>` (e.g., `mypython3`)
- `<install-dir>` (e.g., `/some/environment/`)

By default, uv will automatically download Python versions if they cannot be found on the system.
This behavior can be
[disabled with the `python-downloads` option](#disabling-automatic-python-downloads).

### Python version files

The `.python-version` file can be used to create a default Python version request. uv searches for a
`.python-version` file in the working directory and each of its parents. If none is found, uv will
check the user-level configuration directory. Any of the request formats described above can be
used, though use of a version number is recommended for interoperability with other tools.

A `.python-version` file can be created in the current directory with the
[`uv python pin`](../reference/cli.md/#uv-python-pin) command.

A global `.python-version` file can be created in the user configuration directory with the
[`uv python pin --global`](../reference/cli.md/#uv-python-pin) command.

Discovery of `.python-version` files can be disabled with `--no-config`.

uv will not search for `.python-version` files beyond project or workspace boundaries (except the
user configuration directory).

## Installing a Python version

uv bundles a list of downloadable CPython and PyPy distributions for macOS, Linux, and Windows.

!!! tip

    By default, Python versions are automatically downloaded as needed without using
    `uv python install`.

To install a Python version at a specific version:

```console
$ uv python install 3.12.3
```

To install the latest patch version:

```console
$ uv python install 3.12
```

To install a version that satisfies constraints:

```console
$ uv python install '>=3.8,<3.10'
```

To install multiple versions:

```console
$ uv python install 3.9 3.10 3.11
```

To install a specific implementation:

```console
$ uv python install pypy
```

All the [Python version request](#requesting-a-version) formats are supported except those that are
used for requesting local interpreters such as a file path.

By default `uv python install` will verify that a managed Python version is installed or install the
latest version. If a `.python-version` file is present, uv will install the Python version listed in
the file. A project that requires multiple Python versions may define a `.python-versions` file. If
present, uv will install all the Python versions listed in the file.

!!! important

    The available Python versions are frozen for each uv release. To install new Python versions,
    you may need upgrade uv.

### Installing Python executables

uv installs Python executables into your `PATH` by default, e.g., `uv python install 3.12` will
install a Python executable into `~/.local/bin`, e.g., as `python3.12`.

!!! tip

    If `~/.local/bin` is not in your `PATH`, you can add it with `uv tool update-shell`.

To install `python` and `python3` executables, include the experimental `--default` option:

```console
$ uv python install 3.12 --default
```

When installing Python executables, uv will only overwrite an existing executable if it is managed
by uv — e.g., if `~/.local/bin/python3.12` exists already uv will not overwrite it without the
`--force` flag.

uv will update executables that it manages. However, it will prefer the latest patch version of each
Python minor version by default. For example:

```console
$ uv python install 3.12.7  # Adds `python3.12` to `~/.local/bin`
$ uv python install 3.12.6  # Does not update `python3.12`
$ uv python install 3.12.8  # Updates `python3.12` to point to 3.12.8
```

## Upgrading Python versions

!!! important

    Support for upgrading Python versions is in _preview_. This means the behavior is experimental
    and subject to change.

    Upgrades are only supported for uv-managed Python versions.

    Upgrades are not currently supported for PyPy and GraalPy.

uv allows transparently upgrading Python versions to the latest patch release, e.g., 3.13.4 to
3.13.5. uv does not allow transparently upgrading across minor Python versions, e.g., 3.12 to 3.13,
because changing minor versions can affect dependency resolution.

uv-managed Python versions can be upgraded to the latest supported patch release with the
`python upgrade` command:

To upgrade a Python version to the latest supported patch release:

```console
$ uv python upgrade 3.12
```

To upgrade all installed Python versions:

```console
$ uv python upgrade
```

After an upgrade, uv will prefer the new version, but will retain the existing version as it may
still be used by virtual environments.

If the Python version was installed with the `python-upgrade` [preview feature](./preview.md)
enabled, e.g., `uv python install 3.12 --preview-features python-upgrade`, virtual environments
using the Python version will be automatically upgraded to the new patch version.

!!! note

    If the virtual environment was created _before_ opting in to the preview mode, it will not be
    included in the automatic upgrades.

If a virtual environment was created with an explicitly requested patch version, e.g.,
`uv venv -p 3.10.8`, it will not be transparently upgraded to a new version.

### Minor version directories

Automatic upgrades for virtual environments are implemented using a directory with the Python minor
version, e.g.:

```
~/.local/share/uv/python/cpython-3.12-macos-aarch64-none
```

which is a symbolic link (on Unix) or junction (on Windows) pointing to a specific patch version:

```console
$ readlink ~/.local/share/uv/python/cpython-3.12-macos-aarch64-none
~/.local/share/uv/python/cpython-3.12.11-macos-aarch64-none
```

If this link is resolved by another tool, e.g., by canonicalizing the Python interpreter path, and
used to create a virtual environment, it will not be automatically upgraded.

## Project Python versions

uv will respect Python requirements defined in `requires-python` in the `pyproject.toml` file during
project command invocations. The first Python version that is compatible with the requirement will
be used, unless a version is otherwise requested, e.g., via a `.python-version` file or the
`--python` flag.

## Viewing available Python versions

To list installed and available Python versions:

```console
$ uv python list
```

To filter the Python versions, provide a request, e.g., to show all Python 3.13 interpreters:

```console
$ uv python list 3.13
```

Or, to show all PyPy interpreters:

```console
$ uv python list pypy
```

By default, downloads for other platforms and old patch versions are hidden.

To view all versions:

```console
$ uv python list --all-versions
```

To view Python versions for other platforms:

```console
$ uv python list --all-platforms
```

To exclude downloads and only show installed Python versions:

```console
$ uv python list --only-installed
```

See the [`uv python list`](../reference/cli.md#uv-python-list) reference for more details.

## Finding a Python executable

To find a Python executable, use the `uv python find` command:

```console
$ uv python find
```

By default, this will display the path to the first available Python executable. See the
[discovery rules](#discovery-of-python-versions) for details about how executables are discovered.

This interface also supports many [request formats](#requesting-a-version), e.g., to find a Python
executable that has a version of 3.11 or newer:

```console
$ uv python find '>=3.11'
```

By default, `uv python find` will include Python versions from virtual environments. If a `.venv`
directory is found in the working directory or any of the parent directories or the `VIRTUAL_ENV`
environment variable is set, it will take precedence over any Python executables on the `PATH`.

To ignore virtual environments, use the `--system` flag:

```console
$ uv python find --system
```

## Discovery of Python versions

When searching for a Python version, the following locations are checked:

- Managed Python installations in the `UV_PYTHON_INSTALL_DIR`.
- A Python interpreter on the `PATH` as `python`, `python3`, or `python3.x` on macOS and Linux, or
  `python.exe` on Windows.
- On Windows, the Python interpreters in the Windows registry and Microsoft Store Python
  interpreters (see `py --list-paths`) that match the requested version.

In some cases, uv allows using a Python version from a virtual environment. In this case, the
virtual environment's interpreter will be checked for compatibility with the request before
searching for an installation as described above. See the
[pip-compatible virtual environment discovery](../pip/environments.md#discovery-of-python-environments)
documentation for details.

When performing discovery, non-executable files will be ignored. Each discovered executable is
queried for metadata to ensure it meets the [requested Python version](#requesting-a-version). If
the query fails, the executable will be skipped. If the executable satisfies the request, it is used
without inspecting additional executables.

When searching for a managed Python version, uv will prefer newer versions first. When searching for
a system Python version, uv will use the first compatible version — not the newest version.

If a Python version cannot be found on the system, uv will check for a compatible managed Python
version download.

## Python pre-releases

Python pre-releases will not be selected by default. Python pre-releases will be used if there is no
other available installation matching the request. For example, if only a pre-release version is
available it will be used but otherwise a stable release version will be used. Similarly, if the
path to a pre-release Python executable is provided then no other Python version matches the request
and the pre-release version will be used.

If a pre-release Python version is available and matches the request, uv will not download a stable
Python version instead.

## Free-threaded Python

uv supports discovering and installing
[free-threaded](https://docs.python.org/3.14/glossary.html#term-free-threading) Python variants in
CPython 3.13+.

Free-threaded Python versions will not be selected by default. Free-threaded Python versions will
only be selected when explicitly requested, e.g., with `3.13t` or `3.13+freethreaded`.

## Debug Python variants

uv supports discovering and installing
[debug builds](https://docs.python.org/3.14/using/configure.html#debug-build) of Python, i.e., with
debug assertions enabled.

!!! important

    Debug builds of Python are slower and are not appropriate for general use.

Debug builds will be used if there is no other available installation matching the request. For
example, if only a debug version is available it will be used but otherwise a stable release version
will be used. Similarly, if the path to a debug Python executable is provided then no other Python
version matches the request and the debug version will be used.

Debug builds of Python can be explicitly requested with, e.g., `3.13d` or `3.13+debug`.

!!! note

    CPython versions installed by uv usually have debug symbols stripped to reduce the distribution
    size. These debug builds do not have debug symbols stripped, which can be useful when debugging
    Python processes with a C-level debugger.

## Disabling automatic Python downloads

By default, uv will automatically download Python versions when needed.

The [`python-downloads`](../reference/settings.md#python-downloads) option can be used to disable
this behavior. By default, it is set to `automatic`; set to `manual` to only allow Python downloads
during `uv python install`.

!!! tip

    The `python-downloads` setting can be set in a
    [persistent configuration file](./configuration-files.md) to change the default behavior, or
    the `--no-python-downloads` flag can be passed to any uv command.

## Requiring or disabling managed Python versions

By default, uv will attempt to use Python versions found on the system and only download managed
Python versions when necessary. To ignore system Python versions, and only use managed Python
versions, use the `--managed-python` flag:

```console
$ uv python list --managed-python
```

Similarly, to ignore managed Python versions and only use system Python versions, use the
`--no-managed-python` flag:

```console
$ uv python list --no-managed-python
```

To change uv's default behavior in a configuration file, use the
[`python-preference` setting](#adjusting-python-version-preferences).

## Adjusting Python version preferences

The [`python-preference`](../reference/settings.md#python-preference) setting determines whether to
prefer using Python installations that are already present on the system, or those that are
downloaded and installed by uv.

By default, the `python-preference` is set to `managed` which prefers managed Python installations
over system Python installations. However, system Python installations are still preferred over
downloading a managed Python version.

The following alternative options are available:

- `only-managed`: Only use managed Python installations; never use system Python installations.
  Equivalent to `--managed-python`.
- `system`: Prefer system Python installations over managed Python installations.
- `only-system`: Only use system Python installations; never use managed Python installations.
  Equivalent to `--no-managed-python`.

!!! note

    Automatic Python version downloads can be [disabled](#disabling-automatic-python-downloads)
    without changing the preference.

## Python implementation support

uv supports the CPython, PyPy, Pyodide, and GraalPy Python implementations. If a Python
implementation is not supported, uv will fail to discover its interpreter.

The implementations may be requested with either the long or short name:

- CPython: `cpython`, `cp`
- PyPy: `pypy`, `pp`
- GraalPy: `graalpy`, `gp`
- Pyodide: `pyodide`

Implementation name requests are not case-sensitive.

See the [Python version request](#requesting-a-version) documentation for more details on the
supported formats.

## Managed Python distributions

uv supports downloading and installing CPython, PyPy, and Pyodide distributions.

### CPython distributions

As Python does not publish official distributable CPython binaries, uv instead uses pre-built
distributions from the Astral
[`python-build-standalone`](https://github.com/astral-sh/python-build-standalone) project.
`python-build-standalone` is also is used in many other Python projects, like
[Rye](https://github.com/astral-sh/rye), [Mise](https://mise.jdx.dev/lang/python.html), and
[bazelbuild/rules_python](https://github.com/bazelbuild/rules_python).

The uv Python distributions are self-contained, highly-portable, and performant. While Python can be
built from source, as in tools like `pyenv`, doing so requires preinstalled system dependencies, and
creating optimized, performant builds (e.g., with PGO and LTO enabled) is very slow.

These distributions have some behavior quirks, generally as a consequence of portability; see the
[`python-build-standalone` quirks](https://gregoryszorc.com/docs/python-build-standalone/main/quirks.html)
documentation for details. Additionally, some platforms may not be supported (e.g., distributions
are not yet available for musl Linux on ARM).

### PyPy distributions

PyPy distributions are provided by the [PyPy project](https://pypy.org).

### Pyodide distributions

Pyodide distributions are provided by the [Pyodide project](https://github.com/pyodide/pyodide).

Pyodide is a port of CPython for the WebAssembly / Emscripten platform.

## Registration in the Windows registry

On Windows, installation of managed Python versions will register them with the Windows registry as
defined by [PEP 514](https://peps.python.org/pep-0514/).

After installation, the Python versions can be selected with the `py` launcher, e.g.:

```console
$ uv python install 3.13.1
$ py -V:Astral/CPython3.13.1
```

On uninstall, uv will remove the registry entry for the target version as well as any broken
registry entries.

    # Resolution

Resolution is the process of taking a list of requirements and converting them to a list of package
versions that fulfill the requirements. Resolution requires recursively searching for compatible
versions of packages, ensuring that the requested requirements are fulfilled and that the
requirements of the requested packages are compatible.

## Dependencies

Most projects and packages have dependencies. Dependencies are other packages that are necessary in
order for the current package to work. A package defines its dependencies as _requirements_, roughly
a combination of a package name and acceptable versions. The dependencies defined by the current
project are called _direct dependencies_. The dependencies added by each dependency of the current
project are called _indirect_ or _transitive dependencies_.

!!! note

    See the [dependency specifiers
    page](https://packaging.python.org/en/latest/specifications/dependency-specifiers/)
    in the Python Packaging documentation for details about dependencies.

## Basic examples

To help demonstrate the resolution process, consider the following dependencies:

<!-- prettier-ignore -->
- The project depends on `foo` and `bar`.
- `foo` has one version, 1.0.0:
    - `foo 1.0.0` depends on `lib>=1.0.0`.
- `bar` has one version, 1.0.0:
    - `bar 1.0.0` depends on `lib>=2.0.0`.
- `lib` has two versions, 1.0.0 and 2.0.0. Both versions have no dependencies.

In this example, the resolver must find a set of package versions which satisfies the project
requirements. Since there is only one version of both `foo` and `bar`, those will be used. The
resolution must also include the transitive dependencies, so a version of `lib` must be chosen.
`foo 1.0.0` allows all available versions of `lib`, but `bar 1.0.0` requires `lib>=2.0.0` so
`lib 2.0.0` must be used.

In some resolutions, there may be more than one valid solution. Consider the following dependencies:

<!-- prettier-ignore -->
- The project depends on `foo` and `bar`.
- `foo` has two versions, 1.0.0 and 2.0.0:
    - `foo 1.0.0` has no dependencies.
    - `foo 2.0.0` depends on `lib==2.0.0`.
- `bar` has two versions, 1.0.0 and 2.0.0:
    - `bar 1.0.0` has no dependencies.
    - `bar 2.0.0` depends on `lib==1.0.0`
- `lib` has two versions, 1.0.0 and 2.0.0. Both versions have no dependencies.

In this example, some version of both `foo` and `bar` must be selected; however, determining which
version requires considering the dependencies of each version of `foo` and `bar`. `foo 2.0.0` and
`bar 2.0.0` cannot be installed together as they conflict on their required version of `lib`, so the
resolver must select either `foo 1.0.0` (along with `bar 2.0.0`) or `bar 1.0.0` (along with
`foo 1.0.0`). Both are valid solutions, and different resolution algorithms may yield either result.

## Platform markers

Markers allow attaching an expression to requirements that indicate when the dependency should be
used. For example `bar ; python_version < "3.9"` indicates that `bar` should only be installed on
Python 3.8 and earlier.

Markers are used to adjust a package's dependencies based on the current environment or platform.
For example, markers can be used to modify dependencies by operating system, CPU architecture,
Python version, Python implementation, and more.

!!! note

    See the [environment
    markers](https://packaging.python.org/en/latest/specifications/dependency-specifiers/#environment-markers)
    section in the Python Packaging documentation for more details about markers.

Markers are important for resolution because their values change the required dependencies.
Typically, Python package resolvers use the markers of the _current_ platform to determine which
dependencies to use since the package is often being _installed_ on the current platform. However,
for _locking_ dependencies this is problematic — the lockfile would only work for developers using
the same platform the lockfile was created on. To solve this problem, platform-independent, or
"universal" resolvers exist.

uv supports both [platform-specific](#platform-specific-resolution) and
[universal](#universal-resolution) resolution.

## Platform-specific resolution

By default, uv's pip interface, i.e., [`uv pip compile`](../pip/compile.md), produces a resolution
that is platform-specific, like `pip-tools`. There is no way to use platform-specific resolution in
the uv's project interface.

uv also supports resolving for specific, alternate platforms and Python versions with the
`--python-platform` and `--python-version` options. For example, if using Python 3.12 on macOS,
`uv pip compile --python-platform linux --python-version 3.10 requirements.in` can be used to
produce a resolution for Python 3.10 on Linux instead. Unlike universal resolution, during
platform-specific resolution, the provided `--python-version` is the exact python version to use,
not a lower bound.

!!! note

    Python's environment markers expose far more information about the current machine
    than can be expressed by a simple `--python-platform` argument. For example, the `platform_version` marker
    on macOS includes the time at which the kernel was built, which can (in theory) be encoded in
    package requirements. uv's resolver makes a best-effort attempt to generate a resolution that is
    compatible with any machine running on the target `--python-platform`, which should be sufficient for
    most use cases, but may lose fidelity for complex package and platform combinations.

## Universal resolution

uv's lockfile (`uv.lock`) is created with a universal resolution and is portable across platforms.
This ensures that dependencies are locked for everyone working on the project, regardless of
operating system, architecture, and Python version. The uv lockfile is created and modified by
[project](../concepts/projects/index.md) commands such as `uv lock`, `uv sync`, and `uv add`.

Universal resolution is also available in uv's pip interface, i.e.,
[`uv pip compile`](../pip/compile.md), with the `--universal` flag. The resulting requirements file
will contain markers to indicate which platform each dependency is relevant for.

During universal resolution, a package may be listed multiple times with different versions or URLs
if different versions are needed for different platforms — the markers determine which version will
be used. A universal resolution is often more constrained than a platform-specific resolution, since
we need to take the requirements for all markers into account.

During universal resolution, all required packages must be compatible with the _entire_ range of
`requires-python` declared in the `pyproject.toml`. For example, if a project's `requires-python` is
`>=3.8`, resolution will fail if all versions of given dependency require Python 3.9 or later, since
the dependency lacks a usable version for (e.g.) Python 3.8, the lower bound of the project's
supported range. In other words, the project's `requires-python` must be a subset of the
`requires-python` of all its dependencies.

When selecting the compatible version for a given dependency, uv will
([by default](#multi-version-resolution)) attempt to choose the latest compatible version for each
supported Python version. For example, if a project's `requires-python` is `>=3.8`, and the latest
version of a dependency requires Python 3.9 or later, while all prior versions supporting Python
3.8, the resolver will select the latest version for users running Python 3.9 or later, and previous
versions for users running Python 3.8.

When evaluating `requires-python` ranges for dependencies, uv only considers lower bounds and
ignores upper bounds entirely. For example, `>=3.8, <4` is treated as `>=3.8`. Respecting upper
bounds on `requires-python` often leads to formally correct but practically incorrect resolutions,
as, e.g., resolvers will backtrack to the first published version that omits the upper bound (see:
[`Requires-Python` upper limits](https://discuss.python.org/t/requires-python-upper-limits/12663)).

## Limited resolution environments

By default, the universal resolver attempts to solve for all platforms and Python versions.

If your project supports only a limited set of platforms or Python versions, you can constrain the
set of solved platforms via the `environments` setting, which accepts a list of
[PEP 508 environment markers](https://packaging.python.org/en/latest/specifications/dependency-specifiers/#environment-markers).
In other words, you can use the `environments` setting to _reduce_ the set of supported platforms.

For example, to constrain the lockfile to macOS and Linux, and avoid solving for Windows:

```toml title="pyproject.toml"
[tool.uv]
environments = [
    "sys_platform == 'darwin'",
    "sys_platform == 'linux'",
]
```

Or, to avoid solving for alternative Python implementations:

```toml title="pyproject.toml"
[tool.uv]
environments = [
    "implementation_name == 'cpython'"
]
```

Entries in the `environments` setting must be disjoint (i.e., they must not overlap). For example,
`sys_platform == 'darwin'` and `sys_platform == 'linux'` are disjoint, but
`sys_platform == 'darwin'` and `python_version >= '3.9'` are not, since both could be true at the
same time.

## Required environments

In the Python ecosystem, packages can be published as source distributions, built distributions
(wheels), or both; but to install a package, a built distribution is required. If a package lacks a
built distribution, or lacks a distribution for the current platform or Python version (built
distributions are often platform-specific), uv will attempt to build the package from source, then
install the resulting built distribution.

Some packages (like PyTorch) publish built distributions, but omit a source distribution. Such
packages are _only_ installable on platforms for which a built distribution is available. For
example, if a package publishes built distributions for Linux, but not macOS or Windows, then that
package will _only_ be installable on Linux.

Packages that lack source distributions cause problems for universal resolution, since there will
typically be at least one platform or Python version for which the package is not installable.

By default, uv requires each such package to include at least one wheel that is compatible with the
target Python version. The `required-environments` setting can be used to ensure that the resulting
resolution contains wheels for specific platforms, or fails if no such wheels are available. The
setting accepts a list of
[PEP 508 environment markers](https://packaging.python.org/en/latest/specifications/dependency-specifiers/#environment-markers).

While the `environments` setting _limits_ the set of environments that uv will consider when
resolving dependencies, `required-environments` _expands_ the set of platforms that uv _must_
support when resolving dependencies.

For example, `environments = ["sys_platform == 'darwin'"]` would limit uv to solving for macOS (and
ignoring Linux and Windows). On the other hand,
`required-environments = ["sys_platform == 'darwin'"]` would _require_ that any package without a
source distribution include a wheel for macOS in order to be installable (and would fail if no such
wheel is available).

In practice, `required-environments` can be useful for declaring explicit support for non-latest
platforms, since this often requires backtracking past the latest published versions of those
packages. For example, to guarantee that any built distribution-only packages includes support for
Intel macOS:

```toml title="pyproject.toml"
[tool.uv]
required-environments = [
    "sys_platform == 'darwin' and platform_machine == 'x86_64'"
]
```

## Dependency preferences

If resolution output file exists, i.e., a uv lockfile (`uv.lock`) or a requirements output file
(`requirements.txt`), uv will _prefer_ the dependency versions listed there. Similarly, if
installing a package into a virtual environment, uv will prefer the already installed version if
present. This means that locked or installed versions will not change unless an incompatible version
is requested or an upgrade is explicitly requested with `--upgrade`.

## Resolution strategy

By default, uv tries to use the latest version of each package. For example,
`uv pip install flask>=2.0.0` will install the latest version of Flask, e.g., 3.0.0. If
`flask>=2.0.0` is a dependency of the project, only `flask` 3.0.0 will be used. This is important,
for example, because running tests will not check that the project is actually compatible with its
stated lower bound of `flask` 2.0.0.

With `--resolution lowest`, uv will install the lowest possible version for all dependencies, both
direct and indirect (transitive). Alternatively, `--resolution lowest-direct` will use the lowest
compatible versions for all direct dependencies, while using the latest compatible versions for all
other dependencies. uv will always use the latest versions for build dependencies.

For example, given the following `requirements.in` file:

```python title="requirements.in"
flask>=2.0.0
```

Running `uv pip compile requirements.in` would produce the following `requirements.txt` file:

```python title="requirements.txt"
# This file was autogenerated by uv via the following command:
#    uv pip compile requirements.in
blinker==1.7.0
    # via flask
click==8.1.7
    # via flask
flask==3.0.0
itsdangerous==2.1.2
    # via flask
jinja2==3.1.2
    # via flask
markupsafe==2.1.3
    # via
    #   jinja2
    #   werkzeug
werkzeug==3.0.1
    # via flask
```

However, `uv pip compile --resolution lowest requirements.in` would instead produce:

```python title="requirements.in"
# This file was autogenerated by uv via the following command:
#    uv pip compile requirements.in --resolution lowest
click==7.1.2
    # via flask
flask==2.0.0
itsdangerous==2.0.0
    # via flask
jinja2==3.0.0
    # via flask
markupsafe==2.0.0
    # via jinja2
werkzeug==2.0.0
    # via flask
```

When publishing libraries, it is recommended to separately run tests with `--resolution lowest` or
`--resolution lowest-direct` in continuous integration to ensure compatibility with the declared
lower bounds.

## Pre-release handling

By default, uv will accept pre-release versions during dependency resolution in two cases:

1. If the package is a direct dependency, and its version specifiers include a pre-release specifier
   (e.g., `flask>=2.0.0rc1`).
1. If _all_ published versions of a package are pre-releases.

If dependency resolution fails due to a transitive pre-release, uv will prompt use of
`--prerelease allow` to allow pre-releases for all dependencies.

Alternatively, the transitive dependency can be added as a [constraint](#dependency-constraints) or
direct dependency (i.e. in `requirements.in` or `pyproject.toml`) with a pre-release version
specifier (e.g., `flask>=2.0.0rc1`) to opt in to pre-release support for that specific dependency.

Pre-releases are
[notoriously difficult](https://pubgrub-rs-guide.netlify.app/limitations/prerelease_versions) to
model, and are a frequent source of bugs in other packaging tools. uv's pre-release handling is
_intentionally_ limited and requires user opt-in for pre-releases to ensure correctness.

For more details, see
[Pre-release compatibility](../pip/compatibility.md#pre-release-compatibility).

## Multi-version resolution

During universal resolution, a package may be listed multiple times with different versions or URLs
within the same lockfile, since different versions may be needed for different platforms or Python
versions.

The `--fork-strategy` setting can be used to control how uv trades off between (1) minimizing the
number of selected versions and (2) selecting the latest-possible version for each platform. The
former leads to greater consistency across platforms, while the latter leads to use of newer package
versions where possible.

By default (`--fork-strategy requires-python`), uv will optimize for selecting the latest version of
each package for each supported Python version, while minimizing the number of selected versions
across platforms.

For example, when resolving `numpy` with a Python requirement of `>=3.8`, uv would select the
following versions:

```txt
numpy==1.24.4 ; python_version == "3.8"
numpy==2.0.2 ; python_version == "3.9"
numpy==2.2.0 ; python_version >= "3.10"
```

This resolution reflects the fact that NumPy 2.2.0 and later require at least Python 3.10, while
earlier versions are compatible with Python 3.8 and 3.9.

Under `--fork-strategy fewest`, uv will instead minimize the number of selected versions for each
package, preferring older versions that are compatible with a wider range of supported Python
versions or platforms.

For example, when in the scenario above, uv would select `numpy==1.24.4` for all Python versions,
rather than upgrading to `numpy==2.0.2` for Python 3.9 and `numpy==2.2.0` for Python 3.10 and later.

## Dependency constraints

Like pip, uv supports constraint files (`--constraint constraints.txt`) which narrow the set of
acceptable versions for the given packages. Constraint files are similar to requirements files, but
being listed as a constraint alone will not cause a package to be included to the resolution.
Instead, constraints only take effect if a requested package is already pulled in as a direct or
transitive dependency. Constraints are useful for reducing the range of available versions for a
transitive dependency. They can also be used to keep a resolution in sync with some other set of
resolved versions, regardless of which packages are overlapping between the two.

## Dependency overrides

Dependency overrides allow bypassing unsuccessful or undesirable resolutions by overriding a
package's declared dependencies. Overrides are a useful last resort for cases in which you _know_
that a dependency is compatible with a certain version of a package, despite the metadata indicating
otherwise.

For example, if a transitive dependency declares the requirement `pydantic>=1.0,<2.0`, but _does_
work with `pydantic>=2.0`, the user can override the declared dependency by including
`pydantic>=1.0,<3` in the overrides, thereby allowing the resolver to choose a newer version of
`pydantic`.

Concretely, if `pydantic>=1.0,<3` is included as an override, uv will ignore all declared
requirements on `pydantic`, replacing them with the override. In the above example, the
`pydantic>=1.0,<2.0` requirement would be ignored completely, and would instead be replaced with
`pydantic>=1.0,<3`.

While constraints can only _reduce_ the set of acceptable versions for a package, overrides can
_expand_ the set of acceptable versions, providing an escape hatch for erroneous upper version
bounds. As with constraints, overrides do not add a dependency on the package and only take effect
if the package is requested in a direct or transitive dependency.

In a `pyproject.toml`, use `tool.uv.override-dependencies` to define a list of overrides. In the
pip-compatible interface, the `--override` option can be used to pass files with the same format as
constraints files.

If multiple overrides are provided for the same package, they must be differentiated with
[markers](#platform-markers). If a package has a dependency with a marker, it is replaced
unconditionally when using overrides — it does not matter if the marker evaluates to true or false.

## Dependency metadata

During resolution, uv needs to resolve the metadata for each package it encounters, in order to
determine its dependencies. This metadata is often available as a static file in the package index;
however, for packages that only provide source distributions, the metadata may not be available
upfront.

In such cases, uv has to build the package to determine its metadata (e.g., by invoking `setup.py`).
This can introduce a performance penalty during resolution. Further, it imposes the requirement that
the package can be built on all platforms, which may not be true.

For example, you may have a package that should only be built and installed on Linux, but doesn't
build successfully on macOS or Windows. While uv can construct a perfectly valid lockfile for this
scenario, doing so would require building the package, which would fail on non-Linux platforms.

The `tool.uv.dependency-metadata` table can be used to provide static metadata for such dependencies
upfront, thereby allowing uv to skip the build step and use the provided metadata instead.

For example, to provide metadata for `chumpy` upfront, include its `dependency-metadata` in the
`pyproject.toml`:

```toml
[[tool.uv.dependency-metadata]]
name = "chumpy"
version = "0.70"
requires-dist = ["numpy>=1.8.1", "scipy>=0.13.0", "six>=1.11.0"]
```

These declarations are intended for cases in which a package does _not_ declare static metadata
upfront, though they are also useful for packages that require
[disabling build isolation](./projects/config.md#build-isolation) In such cases, it may be easier to
declare the package metadata upfront, rather than creating a custom build environment prior to
resolving the package.

For example, past versions of `flash-attn` did not declare static metadata. By declaring metadata
for `flash-attn` upfront, uv can resolve `flash-attn` without building the package from source
(which itself requires installing `torch`):

```toml
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["flash-attn"]

[tool.uv.sources]
flash-attn = { git = "https://github.com/Dao-AILab/flash-attention", tag = "v2.6.3" }

[[tool.uv.dependency-metadata]]
name = "flash-attn"
version = "2.6.3"
requires-dist = ["torch", "einops"]
```

Like dependency overrides, `tool.uv.dependency-metadata` can also be used for cases in which a
package's metadata is incorrect or incomplete, or when a package is not available in the package
index. While dependency overrides allow overriding the allowed versions of a package globally,
metadata overrides allow overriding the declared metadata of a _specific package_.

!!! note

    The `version` field in `tool.uv.dependency-metadata` is optional for registry-based
    dependencies (when omitted, uv will assume the metadata applies to all versions of the package),
    but _required_ for direct URL dependencies (like Git dependencies).

Entries in the `tool.uv.dependency-metadata` table follow the
[Metadata 2.3](https://packaging.python.org/en/latest/specifications/core-metadata/) specification,
though only `name`, `version`, `requires-dist`, `requires-python`, and `provides-extra` are read by
uv. The `version` field is also considered optional. If omitted, the metadata will be used for all
versions of the specified package.

## Conflicting dependencies

uv requires that all dependencies declared by a project are compatible with each other and resolves
all dependencies together when creating the lockfile. This includes project dependencies, optional
dependencies ("extras"), and dependency groups (development dependencies).

If dependencies declared in one extra are not compatible with those in another extra, uv will fail
to resolve the requirements of the project with an error. For example, consider two sets of optional
dependencies that conflict with one another:

```toml title="pyproject.toml"
[project.optional-dependencies]
extra1 = ["numpy==2.1.2"]
extra2 = ["numpy==2.0.0"]
```

If you run `uv lock` with the above dependencies, resolution will fail:

```console
$ uv lock
  x No solution found when resolving dependencies:
  `-> Because myproject[extra2] depends on numpy==2.0.0 and myproject[extra1] depends on numpy==2.1.2, we can conclude that myproject[extra1] and
      myproject[extra2] are incompatible.
      And because your project requires myproject[extra1] and myproject[extra2], we can conclude that your projects's requirements are unsatisfiable.
```

To work around this, uv supports explicit declaration of conflicts. If you specify that `extra1` and
`extra2` are conflicting, uv will resolve them separately. Specify conflicts in the `tool.uv`
section:

```toml title="pyproject.toml"
[tool.uv]
conflicts = [
    [
      { extra = "extra1" },
      { extra = "extra2" },
    ],
]
```

Now, running `uv lock` will succeed. However, now you cannot install both `extra1` and `extra2` at
the same time:

```console
$ uv sync --extra extra1 --extra extra2
Resolved 3 packages in 14ms
error: extra `extra1`, extra `extra2` are incompatible with the declared conflicts: {`myproject[extra1]`, `myproject[extra2]`}
```

This error occurs because installing both `extra1` and `extra2` would result in installing two
different versions of a package into the same environment.

The above strategy for dealing with conflicting optional dependencies also works with dependency
groups:

```toml title="pyproject.toml"
[dependency-groups]
group1 = ["numpy==2.1.2"]
group2 = ["numpy==2.0.0"]

[tool.uv]
conflicts = [
    [
      { group = "group1" },
      { group = "group2" },
    ],
]
```

The only difference from conflicting extras is that you need to use the `group` key instead of
`extra`.

When using a workspace with multiple projects, the same restrictions apply — uv requires all
workspace members to be compatible with each other. Similarly, conflicts can be declared across
workspace members.

For example, consider the following workspace:

```toml title="member1/pyproject.toml"
[project]
name = "member1"

[project.optional-dependencies]
extra1 = ["numpy==2.1.2"]
```

```toml title="member2/pyproject.toml"
[project]
name = "member2"

[project.optional-dependencies]
extra2 = ["numpy==2.0.0"]
```

To declare a conflict between extras in these different workspace members, use the `package` key:

```toml title="pyproject.toml"
[tool.uv]
conflicts = [
    [
      { package = "member1", extra = "extra1" },
      { package = "member2", extra = "extra2" },
    ],
]
```

It's also possible for the project dependencies (i.e., `project.dependencies`) of one workspace
member to conflict with the extra of another member, for example:

```toml title="member1/pyproject.toml"
[project]
name = "member1"
dependencies = ["numpy==2.1.2"]
```

```toml title="member2/pyproject.toml"
[project]
name = "member2"

[project.optional-dependencies]
extra2 = ["numpy==2.0.0"]
```

This conflict can also be declared using the `package` key:

```toml title="pyproject.toml"
[tool.uv]
conflicts = [
    [
      { package = "member1" },
      { package = "member2", extra = "extra2" },
    ],
]
```

Similarly, it's possible for some workspace members to have conflicting project dependencies:

```toml title="member1/pyproject.toml"
[project]
name = "member1"
dependencies = ["numpy==2.1.2"]
```

```toml title="member2/pyproject.toml"
[project]
name = "member2"
dependencies = ["numpy==2.0.0"]
```

This conflict can also be declared using the `package` key:

```toml title="pyproject.toml"
[tool.uv]
conflicts = [
    [
      { package = "member1" },
      { package = "member2" },
    ],
]
```

These workspace members will not be installable together, e.g., the workspace root cannot define:

```toml title="pyproject.toml"
[project]
name = "root"
dependencies = ["member1", "member2"]
```

## Lower bounds

By default, `uv add` adds lower bounds to dependencies and, when using uv to manage projects, uv
will warn if direct dependencies don't have lower bound.

Lower bounds are not critical in the "happy path", but they are important for cases where there are
dependency conflicts. For example, consider a project that requires two packages and those packages
have conflicting dependencies. The resolver needs to check all combinations of all versions within
the constraints for the two packages — if all of them conflict, an error is reported because the
dependencies are not satisfiable. If there are no lower bounds, the resolver can (and often will)
backtrack down to the oldest version of a package. This isn't only problematic because it's slow,
the old version of the package often fails to build, or the resolver can end up picking a version
that's old enough that it doesn't depend on the conflicting package, but also doesn't work with your
code.

Lower bounds are particularly critical when writing a library. It's important to declare the lowest
version for each dependency that your library works with, and to validate that the bounds are
correct — testing with
[`--resolution lowest` or `--resolution lowest-direct`](#resolution-strategy). Otherwise, a user may
receive an old, incompatible version of one of your library's dependencies and the library will fail
with an unexpected error.

## Reproducible resolutions

uv supports an `--exclude-newer` option to limit resolution to distributions published before a
specific date, allowing reproduction of installations regardless of new package releases. The date
may be specified as an [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html) timestamp (e.g.,
`2006-12-02T02:07:43Z`) or a local date in the same format (e.g., `2006-12-02`) in your system's
configured time zone.

Note the package index must support the `upload-time` field as specified in
[`PEP 700`](https://peps.python.org/pep-0700/). If the field is not present for a given
distribution, the distribution will be treated as unavailable. PyPI provides `upload-time` for all
packages.

To ensure reproducibility, messages for unsatisfiable resolutions will not mention that
distributions were excluded due to the `--exclude-newer` flag — newer distributions will be treated
as if they do not exist.

!!! note

    The `--exclude-newer` option is only applied to packages that are read from a registry (as opposed to, e.g., Git
    dependencies). Further, when using the `uv pip` interface, uv will not downgrade previously installed packages
    unless the `--reinstall` flag is provided, in which case uv will perform a new resolution.

## Source distribution

[PEP 625](https://peps.python.org/pep-0625/) specifies that packages must distribute source
distributions as gzip tarball (`.tar.gz`) archives. Prior to this specification, other archive
formats, which need to be supported for backward compatibility, were also allowed. uv supports
reading and extracting archives in the following formats:

- gzip tarball (`.tar.gz`, `.tgz`)
- bzip2 tarball (`.tar.bz2`, `.tbz`)
- xz tarball (`.tar.xz`, `.txz`)
- zstd tarball (`.tar.zst`)
- lzip tarball (`.tar.lz`)
- lzma tarball (`.tar.lzma`)
- zip (`.zip`)

## Lockfile versioning

The `uv.lock` file uses a versioned schema. The schema version is included in the `version` field of
the lockfile.

Any given version of uv can read and write lockfiles with the same schema version, but will reject
lockfiles with a greater schema version. For example, if your uv version supports schema v1,
`uv lock` will error if it encounters an existing lockfile with schema v2.

uv versions that support schema v2 _may_ be able to read lockfiles with schema v1 if the schema
update was backwards-compatible. However, this is not guaranteed, and uv may exit with an error if
it encounters a lockfile with an outdated schema version.

The schema version is considered part of the public API, and so is only bumped in minor releases, as
a breaking change (see [Versioning](../reference/policies/versioning.md)). As such, all uv patch
versions within a given minor uv release are guaranteed to have full lockfile compatibility. In
other words, lockfiles may only be rejected across minor releases.

The `revision` field of the lockfile is used to track backwards compatible changes to the lockfile.
For example, adding a new field to distributions. Changes to the revision will not cause older
versions of uv to error.

## Learn more

For more details about the internals of the resolver, see the
[resolver reference](../reference/internals/resolver.md) documentation.

    # Tools

Tools are Python packages that provide command-line interfaces.

!!! note

    See the [tools guide](../guides/tools.md) for an introduction to working with the tools
    interface — this document discusses details of tool management.

## The `uv tool` interface

uv includes a dedicated interface for interacting with tools. Tools can be invoked without
installation using `uv tool run`, in which case their dependencies are installed in a temporary
virtual environment isolated from the current project.

Because it is very common to run tools without installing them, a `uvx` alias is provided for
`uv tool run` — the two commands are exactly equivalent. For brevity, the documentation will mostly
refer to `uvx` instead of `uv tool run`.

Tools can also be installed with `uv tool install`, in which case their executables are
[available on the `PATH`](#the-path) — an isolated virtual environment is still used, but it is not
removed when the command completes.

## Execution vs installation

In most cases, executing a tool with `uvx` is more appropriate than installing the tool. Installing
the tool is useful if you need the tool to be available to other programs on your system, e.g., if
some script you do not control requires the tool, or if you are in a Docker image and want to make
the tool available to users.

## Tool environments

When running a tool with `uvx`, a virtual environment is stored in the uv cache directory and is
treated as disposable, i.e., if you run `uv cache clean` the environment will be deleted. The
environment is only cached to reduce the overhead of repeated invocations. If the environment is
removed, a new one will be created automatically.

When installing a tool with `uv tool install`, a virtual environment is created in the uv tools
directory. The environment will not be removed unless the tool is uninstalled. If the environment is
manually deleted, the tool will fail to run.

## Tool versions

Unless a specific version is requested, `uv tool install` will install the latest available of the
requested tool. `uvx` will use the latest available version of the requested tool _on the first
invocation_. After that, `uvx` will use the cached version of the tool unless a different version is
requested, the cache is pruned, or the cache is refreshed.

For example, to run a specific version of Ruff:

```console
$ uvx ruff@0.6.0 --version
ruff 0.6.0
```

A subsequent invocation of `uvx` will use the latest, not the cached, version.

```console
$ uvx ruff --version
ruff 0.6.2
```

But, if a new version of Ruff was released, it would not be used unless the cache was refreshed.

To request the latest version of Ruff and refresh the cache, use the `@latest` suffix:

```console
$ uvx ruff@latest --version
0.6.2
```

Once a tool is installed with `uv tool install`, `uvx` will use the installed version by default.

For example, after installing an older version of Ruff:

```console
$ uv tool install ruff==0.5.0
```

The version of `ruff` and `uvx ruff` is the same:

```console
$ ruff --version
ruff 0.5.0
$ uvx ruff --version
ruff 0.5.0
```

However, you can ignore the installed version by requesting the latest version explicitly, e.g.:

```console
$ uvx ruff@latest --version
0.6.2
```

Or, by using the `--isolated` flag, which will avoid refreshing the cache but ignore the installed
version:

```console
$ uvx --isolated ruff --version
0.6.2
```

`uv tool install` will also respect the `{package}@{version}` and `{package}@latest` specifiers, as
in:

```console
$ uv tool install ruff@latest
$ uv tool install ruff@0.6.0
```

## Tools directory

By default, the uv tools directory is named `tools` and is in the uv application state directory,
e.g., `~/.local/share/uv/tools`. The location may be customized with the `UV_TOOL_DIR` environment
variable.

To display the path to the tool installation directory:

```console
$ uv tool dir
```

Tool environments are placed in a directory with the same name as the tool package, e.g.,
`.../tools/<name>`.

!!! important

    Tool environments are _not_ intended to be mutated directly. It is strongly recommended never to
    mutate a tool environment manually, e.g., with a `pip` operation.

## Upgrading tools

Tool environments may be upgraded via `uv tool upgrade`, or re-created entirely via subsequent
`uv tool install` operations.

To upgrade all packages in a tool environment

```console
$ uv tool upgrade black
```

To upgrade a single package in a tool environment:

```console
$ uv tool upgrade black --upgrade-package click
```

Tool upgrades will respect the version constraints provided when installing the tool. For example,
`uv tool install black >=23,<24` followed by `uv tool upgrade black` will upgrade Black to the
latest version in the range `>=23,<24`.

To instead replace the version constraints, reinstall the tool with `uv tool install`:

```console
$ uv tool install black>=24
```

Similarly, tool upgrades will retain the settings provided when installing the tool. For example,
`uv tool install black --prerelease allow` followed by `uv tool upgrade black` will retain the
`--prerelease allow` setting.

!!! note

    Tool upgrades will reinstall the tool executables, even if they have not changed.

To reinstall packages during upgrade, use the `--reinstall` and `--reinstall-package` options.

To reinstall all packages in a tool environment

```console
$ uv tool upgrade black --reinstall
```

To reinstall a single package in a tool environment:

```console
$ uv tool upgrade black --reinstall-package click
```

## Including additional dependencies

Additional packages can be included during tool execution:

```console
$ uvx --with <extra-package> <tool>
```

And, during tool installation:

```console
$ uv tool install --with <extra-package> <tool-package>
```

The `--with` option can be provided multiple times to include additional packages.

The `--with` option supports package specifications, so a specific version can be requested:

```console
$ uvx --with <extra-package>==<version> <tool-package>
```

The `-w` shorthand can be used in place of the `--with` option:

```console
$ uvx -w <extra-package> <tool-package>
```

If the requested version conflicts with the requirements of the tool package, package resolution
will fail and the command will error.

## Installing executables from additional packages

When installing a tool, you may want to include executables from additional packages in the same
tool environment. This is useful when you have related tools that work together or when you want to
install multiple executables that share dependencies.

The `--with-executables-from` option allows you to specify additional packages whose executables
should be installed alongside the main tool:

```console
$ uv tool install --with-executables-from <package1>,<package2> <tool-package>
```

For example, to install Ansible along with executables from `ansible-core` and `ansible-lint`:

```console
$ uv tool install --with-executables-from ansible-core,ansible-lint ansible
```

This will install all executables from the `ansible`, `ansible-core`, and `ansible-lint` packages
into the same tool environment, making them all available on the `PATH`.

The `--with-executables-from` option can be combined with other installation options:

```console
$ uv tool install --with-executables-from ansible-core --with mkdocs-material ansible
```

Note that `--with-executables-from` differs from `--with` in that:

- `--with` includes additional packages as dependencies but does not install their executables
- `--with-executables-from` includes both the packages as dependencies and installs their
  executables

## Python versions

Each tool environment is linked to a specific Python version. This uses the same Python version
[discovery logic](./python-versions.md#discovery-of-python-versions) as other virtual environments
created by uv, but will ignore non-global Python version requests like `.python-version` files and
the `requires-python` value from a `pyproject.toml`.

The `--python` option can be used to request a specific version. See the
[Python version](./python-versions.md) documentation for more details.

If the Python version used by a tool is _uninstalled_, the tool environment will be broken and the
tool may be unusable.

## Tool executables

Tool executables include all console entry points, script entry points, and binary scripts provided
by a Python package. Tool executables are symlinked into the `bin` directory on Unix and copied on
Windows.

### The `bin` directory

Executables are installed into the user `bin` directory following the XDG standard, e.g.,
`~/.local/bin`. Unlike other directory schemes in uv, the XDG standard is used on _all platforms_
notably including Windows and macOS — there is no clear alternative location to place executables on
these platforms. The installation directory is determined from the first available environment
variable:

- `$UV_TOOL_BIN_DIR`
- `$XDG_BIN_HOME`
- `$XDG_DATA_HOME/../bin`
- `$HOME/.local/bin`

Executables provided by dependencies of tool packages are not installed.

### The `PATH`

The `bin` directory must be in the `PATH` variable for tool executables to be available from the
shell. If it is not in the `PATH`, a warning will be displayed. The `uv tool update-shell` command
can be used to add the `bin` directory to the `PATH` in common shell configuration files.

### Overwriting executables

Installation of tools will not overwrite executables in the `bin` directory that were not previously
installed by uv. For example, if `pipx` has been used to install a tool, `uv tool install` will
fail. The `--force` flag can be used to override this behavior.

## Relationship to `uv run`

The invocation `uv tool run <name>` (or `uvx <name>`) is nearly equivalent to:

```console
$ uv run --no-project --with <name> -- <name>
```

However, there are a couple notable differences when using uv's tool interface:

- The `--with` option is not needed — the required package is inferred from the command name.
- The temporary environment is cached in a dedicated location.
- The `--no-project` flag is not needed — tools are always run isolated from the project.
- If a tool is already installed, `uv tool run` will use the installed version but `uv run` will
  not.

If the tool should not be isolated from the project, e.g., when running `pytest` or `mypy`, then
`uv run` should be used instead of `uv tool run`.

    # Features

uv provides essential features for Python development — from installing Python and hacking on simple
scripts to working on large projects that support multiple Python versions and platforms.

uv's interface can be broken down into sections, which are usable independently or together.

## Python versions

Installing and managing Python itself.

- `uv python install`: Install Python versions.
- `uv python list`: View available Python versions.
- `uv python find`: Find an installed Python version.
- `uv python pin`: Pin the current project to use a specific Python version.
- `uv python uninstall`: Uninstall a Python version.

See the [guide on installing Python](../guides/install-python.md) to get started.

## Scripts

Executing standalone Python scripts, e.g., `example.py`.

- `uv run`: Run a script.
- `uv add --script`: Add a dependency to a script.
- `uv remove --script`: Remove a dependency from a script.

See the [guide on running scripts](../guides/scripts.md) to get started.

## Projects

Creating and working on Python projects, i.e., with a `pyproject.toml`.

- `uv init`: Create a new Python project.
- `uv add`: Add a dependency to the project.
- `uv remove`: Remove a dependency from the project.
- `uv sync`: Sync the project's dependencies with the environment.
- `uv lock`: Create a lockfile for the project's dependencies.
- `uv run`: Run a command in the project environment.
- `uv tree`: View the dependency tree for the project.
- `uv build`: Build the project into distribution archives.
- `uv publish`: Publish the project to a package index.

See the [guide on projects](../guides/projects.md) to get started.

## Tools

Running and installing tools published to Python package indexes, e.g., `ruff` or `black`.

- `uvx` / `uv tool run`: Run a tool in a temporary environment.
- `uv tool install`: Install a tool user-wide.
- `uv tool uninstall`: Uninstall a tool.
- `uv tool list`: List installed tools.
- `uv tool update-shell`: Update the shell to include tool executables.

See the [guide on tools](../guides/tools.md) to get started.

## The pip interface

Manually managing environments and packages — intended to be used in legacy workflows or cases where
the high-level commands do not provide enough control.

Creating virtual environments (replacing `venv` and `virtualenv`):

- `uv venv`: Create a new virtual environment.

See the documentation on [using environments](../pip/environments.md) for details.

Managing packages in an environment (replacing [`pip`](https://github.com/pypa/pip) and
[`pipdeptree`](https://github.com/tox-dev/pipdeptree)):

- `uv pip install`: Install packages into the current environment.
- `uv pip show`: Show details about an installed package.
- `uv pip freeze`: List installed packages and their versions.
- `uv pip check`: Check that the current environment has compatible packages.
- `uv pip list`: List installed packages.
- `uv pip uninstall`: Uninstall packages.
- `uv pip tree`: View the dependency tree for the environment.

See the documentation on [managing packages](../pip/packages.md) for details.

Locking packages in an environment (replacing [`pip-tools`](https://github.com/jazzband/pip-tools)):

- `uv pip compile`: Compile requirements into a lockfile.
- `uv pip sync`: Sync an environment with a lockfile.

See the documentation on [locking environments](../pip/compile.md) for details.

!!! important

    These commands do not exactly implement the interfaces and behavior of the tools they are based on. The further you stray from common workflows, the more likely you are to encounter differences. Consult the [pip-compatibility guide](../pip/compatibility.md) for details.

## Utility

Managing and inspecting uv's state, such as the cache, storage directories, or performing a
self-update:

- `uv cache clean`: Remove cache entries.
- `uv cache prune`: Remove outdated cache entries.
- `uv cache dir`: Show the uv cache directory path.
- `uv tool dir`: Show the uv tool directory path.
- `uv python dir`: Show the uv installed Python versions path.
- `uv self update`: Update uv to the latest version.

## Next steps

Read the [guides](../guides/index.md) for an introduction to each feature, check out the
[concept](../concepts/index.md) pages for in-depth details about uv's features, or learn how to
[get help](./help.md) if you run into any problems.

    # First steps with uv

After [installing uv](./installation.md), you can check that uv is available by running the `uv`
command:

```console
$ uv
An extremely fast Python package manager.

Usage: uv [OPTIONS] <COMMAND>

...
```

You should see a help menu listing the available commands.

## Next steps

Now that you've confirmed uv is installed, check out an [overview of features](./features.md), learn
how to [get help](./help.md) if you run into any problems, or jump to the
[guides](../guides/index.md) to start using uv.

    # Getting help

## Help menus

The `--help` flag can be used to view the help menu for a command, e.g., for `uv`:

```console
$ uv --help
```

To view the help menu for a specific command, e.g., for `uv init`:

```console
$ uv init --help
```

When using the `--help` flag, uv displays a condensed help menu. To view a longer help menu for a
command, use `uv help`:

```console
$ uv help
```

To view the long help menu for a specific command, e.g., for `uv init`:

```console
$ uv help init
```

When using the long help menu, uv will attempt to use `less` or `more` to "page" the output so it is
not all displayed at once. To exit the pager, press `q`.

## Displaying verbose output

The `-v` flag can be used to display verbose output for a command, e.g., for `uv sync`:

```console
$ uv sync -v
```

The `-v` flag can be repeated to increase verbosity, e.g.:

```console
$ uv sync -vv
```

Often, the verbose output will include additional information about why uv is behaving in a certain
way.

## Viewing the version

When seeking help, it's important to determine the version of uv that you're using — sometimes the
problem is already solved in a newer version.

To check the installed version:

```console
$ uv self version
```

The following are also valid:

```console
$ uv --version      # Same output as `uv self version`
$ uv -V             # Will not include the build commit and date
```

!!! note

    Before uv 0.7.0, `uv version` was used instead of `uv self version`.

## Troubleshooting issues

The reference documentation contains a
[troubleshooting guide](../reference/troubleshooting/index.md) for common issues.

## Open an issue on GitHub

The [issue tracker](https://github.com/astral-sh/uv/issues) on GitHub is a good place to report bugs
and request features. Make sure to search for similar issues first, as it is common for someone else
to encounter the same problem.

## Chat on Discord

Astral has a [Discord server](https://discord.com/invite/astral-sh), which is a great place to ask
questions, learn more about uv, and engage with other community members.

    # Getting started

To help you get started with uv, we'll cover a few important topics:

- [Installing uv](./installation.md)
- [First steps after installation](./first-steps.md)
- [An overview of uv's features](./features.md)
- [How to get help](./help.md)

Read on, or jump ahead to another section:

- Get going quickly with [guides](../guides/index.md) for common workflows.
- Learn more about the core [concepts](../concepts/index.md) in uv.
- Use the [reference](../reference/index.md) documentation to find details about something specific.

    # Installing uv

## Installation methods

Install uv with our standalone installers or your package manager of choice.

### Standalone installer

uv provides a standalone installer to download and install uv:

=== "macOS and Linux"

    Use `curl` to download the script and execute it with `sh`:

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

    If your system doesn't have `curl`, you can use `wget`:

    ```console
    $ wget -qO- https://astral.sh/uv/install.sh | sh
    ```

    Request a specific version by including it in the URL:

    ```console
    $ curl -LsSf https://astral.sh/uv/0.8.22/install.sh | sh
    ```

=== "Windows"

    Use `irm` to download the script and execute it with `iex`:

    ```pwsh-session
    PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
    ```

    Changing the [execution policy](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.4#powershell-execution-policies) allows running a script from the internet.

    Request a specific version by including it in the URL:

    ```pwsh-session
    PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/0.8.22/install.ps1 | iex"
    ```

!!! tip

    The installation script may be inspected before use:

    === "macOS and Linux"

        ```console
        $ curl -LsSf https://astral.sh/uv/install.sh | less
        ```

    === "Windows"

        ```pwsh-session
        PS> powershell -c "irm https://astral.sh/uv/install.ps1 | more"
        ```

    Alternatively, the installer or binaries can be downloaded directly from [GitHub](#github-releases).

See the reference documentation on the [installer](../reference/installer.md) for details on
customizing your uv installation.

### PyPI

For convenience, uv is published to [PyPI](https://pypi.org/project/uv/).

If installing from PyPI, we recommend installing uv into an isolated environment, e.g., with `pipx`:

```console
$ pipx install uv
```

However, `pip` can also be used:

```console
$ pip install uv
```

!!! note

    uv ships with prebuilt distributions (wheels) for many platforms; if a wheel is not available for a given
    platform, uv will be built from source, which requires a Rust toolchain. See the
    [contributing setup guide](https://github.com/astral-sh/uv/blob/main/CONTRIBUTING.md#setup)
    for details on building uv from source.

### Homebrew

uv is available in the core Homebrew packages.

```console
$ brew install uv
```

### WinGet

uv is available via [WinGet](https://winstall.app/apps/astral-sh.uv).

```console
$ winget install --id=astral-sh.uv  -e
```

### Scoop

uv is available via [Scoop](https://scoop.sh/#/apps?q=uv).

```console
$ scoop install main/uv
```

### Docker

uv provides a Docker image at
[`ghcr.io/astral-sh/uv`](https://github.com/astral-sh/uv/pkgs/container/uv).

See our guide on [using uv in Docker](../guides/integration/docker.md) for more details.

### GitHub Releases

uv release artifacts can be downloaded directly from
[GitHub Releases](https://github.com/astral-sh/uv/releases).

Each release page includes binaries for all supported platforms as well as instructions for using
the standalone installer via `github.com` instead of `astral.sh`.

### Cargo

uv is available via Cargo, but must be built from Git rather than [crates.io](https://crates.io) due
to its dependency on unpublished crates.

```console
$ cargo install --git https://github.com/astral-sh/uv uv
```

!!! note

    This method builds uv from source, which requires a compatible Rust toolchain.

## Upgrading uv

When uv is installed via the standalone installer, it can update itself on-demand:

```console
$ uv self update
```

!!! tip

    Updating uv will re-run the installer and can modify your shell profiles. To disable this
    behavior, set `UV_NO_MODIFY_PATH=1`.

When another installation method is used, self-updates are disabled. Use the package manager's
upgrade method instead. For example, with `pip`:

```console
$ pip install --upgrade uv
```

## Shell autocompletion

!!! tip

    You can run `echo $SHELL` to help you determine your shell.

To enable shell autocompletion for uv commands, run one of the following:

=== "Bash"

    ```bash
    echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc
    ```

=== "Zsh"

    ```bash
    echo 'eval "$(uv generate-shell-completion zsh)"' >> ~/.zshrc
    ```

=== "fish"

    ```bash
    echo 'uv generate-shell-completion fish | source' > ~/.config/fish/completions/uv.fish
    ```

=== "Elvish"

    ```bash
    echo 'eval (uv generate-shell-completion elvish | slurp)' >> ~/.elvish/rc.elv
    ```

=== "PowerShell / pwsh"

    ```powershell
    if (!(Test-Path -Path $PROFILE)) {
      New-Item -ItemType File -Path $PROFILE -Force
    }
    Add-Content -Path $PROFILE -Value '(& uv generate-shell-completion powershell) | Out-String | Invoke-Expression'
    ```

To enable shell autocompletion for uvx, run one of the following:

=== "Bash"

    ```bash
    echo 'eval "$(uvx --generate-shell-completion bash)"' >> ~/.bashrc
    ```

=== "Zsh"

    ```bash
    echo 'eval "$(uvx --generate-shell-completion zsh)"' >> ~/.zshrc
    ```

=== "fish"

    ```bash
    echo 'uvx --generate-shell-completion fish | source' > ~/.config/fish/completions/uvx.fish
    ```

=== "Elvish"

    ```bash
    echo 'eval (uvx --generate-shell-completion elvish | slurp)' >> ~/.elvish/rc.elv
    ```

=== "PowerShell / pwsh"

    ```powershell
    if (!(Test-Path -Path $PROFILE)) {
      New-Item -ItemType File -Path $PROFILE -Force
    }
    Add-Content -Path $PROFILE -Value '(& uvx --generate-shell-completion powershell) | Out-String | Invoke-Expression'
    ```

Then restart the shell or source the shell config file.

## Uninstallation

If you need to remove uv from your system, follow these steps:

1.  Clean up stored data (optional):

    ```console
    $ uv cache clean
    $ rm -r "$(uv python dir)"
    $ rm -r "$(uv tool dir)"
    ```

    !!! tip

        Before removing the binaries, you may want to remove any data that uv has stored.

2.  Remove the uv, uvx, and uvw binaries:

    === "macOS and Linux"

        ```console
        $ rm ~/.local/bin/uv ~/.local/bin/uvx
        ```

    === "Windows"

        ```pwsh-session
        PS> rm $HOME\.local\bin\uv.exe
        PS> rm $HOME\.local\bin\uvx.exe
        PS> rm $HOME\.local\bin\uvw.exe
        ```

    !!! note

        Prior to 0.5.0, uv was installed into `~/.cargo/bin`. The binaries can be removed from there to
        uninstall. Upgrading from an older version will not automatically remove the binaries from
        `~/.cargo/bin`.

## Next steps

See the [first steps](./first-steps.md) or jump straight to the [guides](../guides/index.md) to
start using uv.

    # Guides overview

Check out one of the core guides to get started:

- [Installing Python versions](./install-python.md)
- [Running scripts and declaring dependencies](./scripts.md)
- [Running and installing applications as tools](./tools.md)
- [Creating and working on projects](./projects.md)
- [Building and publishing packages](./package.md)
- [Integrate uv with other software, e.g., Docker, GitHub, PyTorch, and more](./integration/index.md)

Or, explore the [concept documentation](../concepts/index.md) for comprehensive breakdown of each
feature.

    ---
title: Installing and managing Python
description:
  A guide to using uv to install Python, including requesting specific versions, automatic
  installation, viewing installed versions, and more.
---

# Installing Python

If Python is already installed on your system, uv will
[detect and use](#using-existing-python-versions) it without configuration. However, uv can also
install and manage Python versions. uv [automatically installs](#automatic-python-downloads) missing
Python versions as needed — you don't need to install Python to get started.

## Getting started

To install the latest Python version:

```console
$ uv python install
```

!!! note

    Python does not publish official distributable binaries. As such, uv uses distributions from the Astral [`python-build-standalone`](https://github.com/astral-sh/python-build-standalone) project. See the [Python distributions](../concepts/python-versions.md#managed-python-distributions) documentation for more details.

Once Python is installed, it will be used by `uv` commands automatically. uv also adds the installed
version to your `PATH`:

```console
$ python3.13
```

uv only installs a _versioned_ executable by default. To install `python` and `python3` executables,
include the experimental `--default` option:

```console
$ uv python install --default
```

!!! tip

    See the documentation on [installing Python executables](../concepts/python-versions.md#installing-python-executables)
    for more details.

## Installing a specific version

To install a specific Python version:

```console
$ uv python install 3.12
```

To install multiple Python versions:

```console
$ uv python install 3.11 3.12
```

To install an alternative Python implementation, e.g., PyPy:

```console
$ uv python install pypy@3.10
```

See the [`python install`](../concepts/python-versions.md#installing-a-python-version) documentation
for more details.

## Reinstalling Python

To reinstall uv-managed Python versions, use `--reinstall`, e.g.:

```console
$ uv python install --reinstall
```

This will reinstall all previously installed Python versions. Improvements are constantly being
added to the Python distributions, so reinstalling may resolve bugs even if the Python version does
not change.

## Viewing Python installations

To view available and installed Python versions:

```console
$ uv python list
```

See the [`python list`](../concepts/python-versions.md#viewing-available-python-versions)
documentation for more details.

## Automatic Python downloads

Python does not need to be explicitly installed to use uv. By default, uv will automatically
download Python versions when they are required. For example, the following would download Python
3.12 if it was not installed:

```console
$ uvx python@3.12 -c "print('hello world')"
```

Even if a specific Python version is not requested, uv will download the latest version on demand.
For example, if there are no Python versions on your system, the following will install Python
before creating a new virtual environment:

```console
$ uv venv
```

!!! tip

    Automatic Python downloads can be [easily disabled](../concepts/python-versions.md#disabling-automatic-python-downloads) if you want more control over when Python is downloaded.

<!-- TODO(zanieb): Restore when Python shim management is added
Note that when an automatic Python installation occurs, the `python` command will not be added to the shell. Use `uv python install-shim` to ensure the `python` shim is installed.
-->

## Using existing Python versions

uv will use existing Python installations if present on your system. There is no configuration
necessary for this behavior: uv will use the system Python if it satisfies the requirements of the
command invocation. See the
[Python discovery](../concepts/python-versions.md#discovery-of-python-versions) documentation for
details.

To force uv to use the system Python, provide the `--no-managed-python` flag. See the
[Python version preference](../concepts/python-versions.md#requiring-or-disabling-managed-python-versions)
documentation for more details.

## Upgrading Python versions

!!! important

    Support for upgrading Python patch versions is in _preview_. This means the behavior is
    experimental and subject to change.

To upgrade a Python version to the latest supported patch release:

```console
$ uv python upgrade 3.12
```

To upgrade all uv-managed Python versions:

```console
$ uv python upgrade
```

See the [`python upgrade`](../concepts/python-versions.md#upgrading-python-versions) documentation
for more details.

## Next steps

To learn more about `uv python`, see the [Python version concept](../concepts/python-versions.md)
page and the [command reference](../reference/cli.md#uv-python).

Or, read on to learn how to [run scripts](./scripts.md) and invoke Python with uv.

    ---
title: Using alternative package indexes
description:
  A guide to using alternative package indexes with uv, including Azure Artifacts, Google Artifact
  Registry, AWS CodeArtifact, and more.
---

# Using alternative package indexes

While uv uses the official Python Package Index (PyPI) by default, it also supports
[alternative package indexes](../../concepts/indexes.md). Most alternative indexes require various
forms of authentication, which require some initial setup.

!!! important

    If using the pip interface, please read the documentation
    on [using multiple indexes](../../pip/compatibility.md#packages-that-exist-on-multiple-indexes)
    in uv — the default behavior is different from pip to prevent dependency confusion attacks, but
    this means that uv may not find the versions of a package as you'd expect.

## Azure Artifacts

uv can install packages from
[Azure Artifacts](https://learn.microsoft.com/en-us/azure/devops/artifacts/start-using-azure-artifacts?view=azure-devops&tabs=nuget%2Cnugetserver),
either by using a
[Personal Access Token](https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows)
(PAT), or using the [`keyring`](https://github.com/jaraco/keyring) package.

To use Azure Artifacts, add the index to your project:

```toml title="pyproject.toml"
[[tool.uv.index]]
name = "private-registry"
url = "https://pkgs.dev.azure.com/<ORGANIZATION>/<PROJECT>/_packaging/<FEED>/pypi/simple/"
```

### Authenticate with an Azure access token

If there is a personal access token (PAT) available (e.g.,
[`$(System.AccessToken)` in an Azure pipeline](https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemaccesstoken)),
credentials can be provided via "Basic" HTTP authentication scheme. Include the PAT in the password
field of the URL. A username must be included as well, but can be any string.

For example, with the token stored in the `$AZURE_ARTIFACTS_TOKEN` environment variable, set
credentials for the index with:

```bash
export UV_INDEX_PRIVATE_REGISTRY_USERNAME=dummy
export UV_INDEX_PRIVATE_REGISTRY_PASSWORD="$AZURE_ARTIFACTS_TOKEN"
```

!!! note

    `PRIVATE_REGISTRY` should match the name of the index defined in your `pyproject.toml`.

### Authenticate with `keyring` and `artifacts-keyring`

You can also authenticate to Artifacts using [`keyring`](https://github.com/jaraco/keyring) package
with the [`artifacts-keyring` plugin](https://github.com/Microsoft/artifacts-keyring). Because these
two packages are required to authenticate to Azure Artifacts, they must be pre-installed from a
source other than Artifacts.

The `artifacts-keyring` plugin wraps the
[Azure Artifacts Credential Provider tool](https://github.com/microsoft/artifacts-credprovider). The
credential provider supports a few different authentication modes including interactive login — see
the [tool's documentation](https://github.com/microsoft/artifacts-credprovider) for information on
configuration.

uv only supports using the `keyring` package in
[subprocess mode](../../reference/settings.md#keyring-provider). The `keyring` executable must be in
the `PATH`, i.e., installed globally or in the active environment. The `keyring` CLI requires a
username in the URL, and it must be `VssSessionToken`.

```bash
# Pre-install keyring and the Artifacts plugin from the public PyPI
uv tool install keyring --with artifacts-keyring

# Enable keyring authentication
export UV_KEYRING_PROVIDER=subprocess

# Set the username for the index
export UV_INDEX_PRIVATE_REGISTRY_USERNAME=VssSessionToken
```

!!! note

    The [`tool.uv.keyring-provider`](../../reference/settings.md#keyring-provider)
    setting can be used to enable keyring in your `uv.toml` or `pyproject.toml`.

    Similarly, the username for the index can be added directly to the index URL.

### Publishing packages to Azure Artifacts

If you also want to publish your own packages to Azure Artifacts, you can use `uv publish` as
described in the [Building and publishing guide](../package.md).

First, add a `publish-url` to the index you want to publish packages to. For example:

```toml title="pyproject.toml" hl_lines="4"
[[tool.uv.index]]
name = "private-registry"
url = "https://pkgs.dev.azure.com/<ORGANIZATION>/<PROJECT>/_packaging/<FEED>/pypi/simple/"
publish-url = "https://pkgs.dev.azure.com/<ORGANIZATION>/<PROJECT>/_packaging/<FEED>/pypi/upload/"
```

Then, configure credentials (if not using keyring):

```console
$ export UV_PUBLISH_USERNAME=dummy
$ export UV_PUBLISH_PASSWORD="$AZURE_ARTIFACTS_TOKEN"
```

And publish the package:

```console
$ uv publish --index private-registry
```

To use `uv publish` without adding the `publish-url` to the project, you can set `UV_PUBLISH_URL`:

```console
$ export UV_PUBLISH_URL=https://pkgs.dev.azure.com/<ORGANIZATION>/<PROJECT>/_packaging/<FEED>/pypi/upload/
$ uv publish
```

Note this method is not preferable because uv cannot check if the package is already published
before uploading artifacts.

## Google Artifact Registry

uv can install packages from
[Google Artifact Registry](https://cloud.google.com/artifact-registry/docs), either by using an
access token, or using the [`keyring`](https://github.com/jaraco/keyring) package.

!!! note

    This guide assumes that [`gcloud`](https://cloud.google.com/sdk/gcloud) CLI is installed and
    authenticated.

To use Google Artifact Registry, add the index to your project:

```toml title="pyproject.toml"
[[tool.uv.index]]
name = "private-registry"
url = "https://<REGION>-python.pkg.dev/<PROJECT>/<REPOSITORY>/simple/"
```

### Authenticate with a Google access token

Credentials can be provided via "Basic" HTTP authentication scheme. Include access token in the
password field of the URL. Username must be `oauth2accesstoken`, otherwise authentication will fail.

Generate a token with `gcloud`:

```bash
export ARTIFACT_REGISTRY_TOKEN=$(
    gcloud auth application-default print-access-token
)
```

!!! note

    You might need to pass extra parameters to properly generate the token (like `--project`), this
    is a basic example.

Then set credentials for the index with:

```bash
export UV_INDEX_PRIVATE_REGISTRY_USERNAME=oauth2accesstoken
export UV_INDEX_PRIVATE_REGISTRY_PASSWORD="$ARTIFACT_REGISTRY_TOKEN"
```

!!! note

    `PRIVATE_REGISTRY` should match the name of the index defined in your `pyproject.toml`.

### Authenticate with `keyring` and `keyrings.google-artifactregistry-auth`

You can also authenticate to Artifact Registry using [`keyring`](https://github.com/jaraco/keyring)
package with the
[`keyrings.google-artifactregistry-auth` plugin](https://github.com/GoogleCloudPlatform/artifact-registry-python-tools).
Because these two packages are required to authenticate to Artifact Registry, they must be
pre-installed from a source other than Artifact Registry.

The `keyrings.google-artifactregistry-auth` plugin wraps
[gcloud CLI](https://cloud.google.com/sdk/gcloud) to generate short-lived access tokens, securely
store them in system keyring, and refresh them when they are expired.

uv only supports using the `keyring` package in
[subprocess mode](../../reference/settings.md#keyring-provider). The `keyring` executable must be in
the `PATH`, i.e., installed globally or in the active environment. The `keyring` CLI requires a
username in the URL and it must be `oauth2accesstoken`.

```bash
# Pre-install keyring and Artifact Registry plugin from the public PyPI
uv tool install keyring --with keyrings.google-artifactregistry-auth

# Enable keyring authentication
export UV_KEYRING_PROVIDER=subprocess

# Set the username for the index
export UV_INDEX_PRIVATE_REGISTRY_USERNAME=oauth2accesstoken
```

!!! note

    The [`tool.uv.keyring-provider`](../../reference/settings.md#keyring-provider)
    setting can be used to enable keyring in your `uv.toml` or `pyproject.toml`.

    Similarly, the username for the index can be added directly to the index URL.

### Publishing packages to Google Artifact Registry

If you also want to publish your own packages to Google Artifact Registry, you can use `uv publish`
as described in the [Building and publishing guide](../package.md).

First, add a `publish-url` to the index you want to publish packages to. For example:

```toml title="pyproject.toml" hl_lines="4"
[[tool.uv.index]]
name = "private-registry"
url = "https://<REGION>-python.pkg.dev/<PROJECT>/<REPOSITORY>/simple/"
publish-url = "https://<REGION>-python.pkg.dev/<PROJECT>/<REPOSITORY>/"
```

Then, configure credentials (if not using keyring):

```console
$ export UV_PUBLISH_USERNAME=oauth2accesstoken
$ export UV_PUBLISH_PASSWORD="$ARTIFACT_REGISTRY_TOKEN"
```

And publish the package:

```console
$ uv publish --index private-registry
```

To use `uv publish` without adding the `publish-url` to the project, you can set `UV_PUBLISH_URL`:

```console
$ export UV_PUBLISH_URL=https://<REGION>-python.pkg.dev/<PROJECT>/<REPOSITORY>/
$ uv publish
```

Note this method is not preferable because uv cannot check if the package is already published
before uploading artifacts.

## AWS CodeArtifact

uv can install packages from
[AWS CodeArtifact](https://docs.aws.amazon.com/codeartifact/latest/ug/using-python.html), either by
using an access token, or using the [`keyring`](https://github.com/jaraco/keyring) package.

!!! note

    This guide assumes that [`awscli`](https://aws.amazon.com/cli/) is installed and authenticated.

The index can be declared like so:

```toml title="pyproject.toml"
[[tool.uv.index]]
name = "private-registry"
url = "https://<DOMAIN>-<ACCOUNT_ID>.d.codeartifact.<REGION>.amazonaws.com/pypi/<REPOSITORY>/simple/"
```

### Authenticate with an AWS access token

Credentials can be provided via "Basic" HTTP authentication scheme. Include access token in the
password field of the URL. Username must be `aws`, otherwise authentication will fail.

Generate a token with `awscli`:

```bash
export AWS_CODEARTIFACT_TOKEN="$(
    aws codeartifact get-authorization-token \
    --domain <DOMAIN> \
    --domain-owner <ACCOUNT_ID> \
    --query authorizationToken \
    --output text
)"
```

!!! note

    You might need to pass extra parameters to properly generate the token (like `--region`), this
    is a basic example.

Then set credentials for the index with:

```bash
export UV_INDEX_PRIVATE_REGISTRY_USERNAME=aws
export UV_INDEX_PRIVATE_REGISTRY_PASSWORD="$AWS_CODEARTIFACT_TOKEN"
```

!!! note

    `PRIVATE_REGISTRY` should match the name of the index defined in your `pyproject.toml`.

### Authenticate with `keyring` and `keyrings.codeartifact`

You can also authenticate to Artifact Registry using [`keyring`](https://github.com/jaraco/keyring)
package with the [`keyrings.codeartifact` plugin](https://github.com/jmkeyes/keyrings.codeartifact).
Because these two packages are required to authenticate to Artifact Registry, they must be
pre-installed from a source other than Artifact Registry.

The `keyrings.codeartifact` plugin wraps [boto3](https://pypi.org/project/boto3/) to generate
short-lived access tokens, securely store them in system keyring, and refresh them when they are
expired.

uv only supports using the `keyring` package in
[subprocess mode](../../reference/settings.md#keyring-provider). The `keyring` executable must be in
the `PATH`, i.e., installed globally or in the active environment. The `keyring` CLI requires a
username in the URL and it must be `aws`.

```bash
# Pre-install keyring and AWS CodeArtifact plugin from the public PyPI
uv tool install keyring --with keyrings.codeartifact

# Enable keyring authentication
export UV_KEYRING_PROVIDER=subprocess

# Set the username for the index
export UV_INDEX_PRIVATE_REGISTRY_USERNAME=aws
```

!!! note

    The [`tool.uv.keyring-provider`](../../reference/settings.md#keyring-provider)
    setting can be used to enable keyring in your `uv.toml` or `pyproject.toml`.

    Similarly, the username for the index can be added directly to the index URL.

### Publishing packages to AWS CodeArtifact

If you also want to publish your own packages to AWS CodeArtifact, you can use `uv publish` as
described in the [Building and publishing guide](../package.md).

First, add a `publish-url` to the index you want to publish packages to. For example:

```toml title="pyproject.toml" hl_lines="4"
[[tool.uv.index]]
name = "private-registry"
url = "https://<DOMAIN>-<ACCOUNT_ID>.d.codeartifact.<REGION>.amazonaws.com/pypi/<REPOSITORY>/simple/"
publish-url = "https://<DOMAIN>-<ACCOUNT_ID>.d.codeartifact.<REGION>.amazonaws.com/pypi/<REPOSITORY>/"
```

Then, configure credentials (if not using keyring):

```console
$ export UV_PUBLISH_USERNAME=aws
$ export UV_PUBLISH_PASSWORD="$AWS_CODEARTIFACT_TOKEN"
```

And publish the package:

```console
$ uv publish --index private-registry
```

To use `uv publish` without adding the `publish-url` to the project, you can set `UV_PUBLISH_URL`:

```console
$ export UV_PUBLISH_URL=https://<DOMAIN>-<ACCOUNT_ID>.d.codeartifact.<REGION>.amazonaws.com/pypi/<REPOSITORY>/
$ uv publish
```

Note this method is not preferable because uv cannot check if the package is already published
before uploading artifacts.

## JFrog Artifactory

uv can install packages from JFrog Artifactory, either by using a username and password or a JWT
token.

To use it, add the index to your project:

```toml title="pyproject.toml"
[[tool.uv.index]]
name = "private-registry"
url = "https://<organization>.jfrog.io/artifactory/api/pypi/<repository>/simple"
```

### Authenticate with username and password

```console
$ export UV_INDEX_PRIVATE_REGISTRY_USERNAME="<username>"
$ export UV_INDEX_PRIVATE_REGISTRY_PASSWORD="<password>"
```

### Authenticate with JWT token

```console
$ export UV_INDEX_PRIVATE_REGISTRY_USERNAME=""
$ export UV_INDEX_PRIVATE_REGISTRY_PASSWORD="$JFROG_JWT_TOKEN"
```

!!! note

    Replace `PRIVATE_REGISTRY` in the environment variable names with the actual index name defined in your `pyproject.toml`.

### Publishing packages to JFrog Artifactory

Add a `publish-url` to your index definition:

```toml title="pyproject.toml"
[[tool.uv.index]]
name = "private-registry"
url = "https://<organization>.jfrog.io/artifactory/api/pypi/<repository>/simple"
publish-url = "https://<organization>.jfrog.io/artifactory/api/pypi/<repository>"
```

!!! important

    If you use `--token "$JFROG_TOKEN"` or `UV_PUBLISH_TOKEN` with JFrog, you will receive a
    401 Unauthorized error as JFrog requires an empty username but uv passes `__token__` for as
    the username when `--token` is used.

To authenticate, pass your token as the password and set the username to an empty string:

```console
$ uv publish --index <index_name> -u "" -p "$JFROG_TOKEN"
```

Alternatively, you can set environment variables:

```console
$ export UV_PUBLISH_USERNAME=""
$ export UV_PUBLISH_PASSWORD="$JFROG_TOKEN"
$ uv publish --index private-registry
```

!!! note

    The publish environment variables (`UV_PUBLISH_USERNAME` and `UV_PUBLISH_PASSWORD`) do not include the index name.

    ---
title: Using uv with AWS Lambda
description:
  A complete guide to using uv with AWS Lambda to manage Python dependencies and deploy serverless
  functions via Docker containers or zip archives.
---

# Using uv with AWS Lambda

[AWS Lambda](https://aws.amazon.com/lambda/) is a serverless computing service that lets you run
code without provisioning or managing servers.

You can use uv with AWS Lambda to manage your Python dependencies, build your deployment package,
and deploy your Lambda functions.

!!! tip

    Check out the [`uv-aws-lambda-example`](https://github.com/astral-sh/uv-aws-lambda-example) project for
    an example of best practices when using uv to deploy an application to AWS Lambda.

## Getting started

To start, assume we have a minimal FastAPI application with the following structure:

```plaintext
project
├── pyproject.toml
└── app
    ├── __init__.py
    └── main.py
```

Where the `pyproject.toml` contains:

```toml title="pyproject.toml"
[project]
name = "uv-aws-lambda-example"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
    # FastAPI is a modern web framework for building APIs with Python.
    "fastapi",
    # Mangum is a library that adapts ASGI applications to AWS Lambda and API Gateway.
    "mangum",
]

[dependency-groups]
dev = [
    # In development mode, include the FastAPI development server.
    "fastapi[standard]>=0.115",
]
```

And the `main.py` file contains:

```python title="app/main.py"
import logging

from fastapi import FastAPI
from mangum import Mangum

logger = logging.getLogger()
logger.setLevel(logging.INFO)

app = FastAPI()
handler = Mangum(app)


@app.get("/")
async def root() -> str:
    return "Hello, world!"
```

We can run this application locally with:

```console
$ uv run fastapi dev
```

From there, opening http://127.0.0.1:8000/ in a web browser will display "Hello, world!"

## Deploying a Docker image

To deploy to AWS Lambda, we need to build a container image that includes the application code and
dependencies in a single output directory.

We'll follow the principles outlined in the [Docker guide](./docker.md) (in particular, a
multi-stage build) to ensure that the final image is as small and cache-friendly as possible.

In the first stage, we'll populate a single directory with all application code and dependencies. In
the second stage, we'll copy this directory over to the final image, omitting the build tools and
other unnecessary files.

```dockerfile title="Dockerfile"
FROM ghcr.io/astral-sh/uv:0.8.22 AS uv

# First, bundle the dependencies into the task root.
FROM public.ecr.aws/lambda/python:3.13 AS builder

# Enable bytecode compilation, to improve cold-start performance.
ENV UV_COMPILE_BYTECODE=1

# Disable installer metadata, to create a deterministic layer.
ENV UV_NO_INSTALLER_METADATA=1

# Enable copy mode to support bind mount caching.
ENV UV_LINK_MODE=copy

# Bundle the dependencies into the Lambda task root via `uv pip install --target`.
#
# Omit any local packages (`--no-emit-workspace`) and development dependencies (`--no-dev`).
# This ensures that the Docker layer cache is only invalidated when the `pyproject.toml` or `uv.lock`
# files change, but remains robust to changes in the application code.
RUN --mount=from=uv,source=/uv,target=/bin/uv \
    --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    uv export --frozen --no-emit-workspace --no-dev --no-editable -o requirements.txt && \
    uv pip install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"

FROM public.ecr.aws/lambda/python:3.13

# Copy the runtime dependencies from the builder stage.
COPY --from=builder ${LAMBDA_TASK_ROOT} ${LAMBDA_TASK_ROOT}

# Copy the application code.
COPY ./app ${LAMBDA_TASK_ROOT}/app

# Set the AWS Lambda handler.
CMD ["app.main.handler"]
```

!!! tip

    To deploy to ARM-based AWS Lambda runtimes, replace `public.ecr.aws/lambda/python:3.13` with `public.ecr.aws/lambda/python:3.13-arm64`.

We can build the image with, e.g.:

```console
$ uv lock
$ docker build -t fastapi-app .
```

The core benefits of this Dockerfile structure are as follows:

1. **Minimal image size.** By using a multi-stage build, we can ensure that the final image only
   includes the application code and dependencies. For example, the uv binary itself is not included
   in the final image.
2. **Maximal cache reuse.** By installing application dependencies separately from the application
   code, we can ensure that the Docker layer cache is only invalidated when the dependencies change.

Concretely, rebuilding the image after modifying the application source code can reuse the cached
layers, resulting in millisecond builds:

```console
 => [internal] load build definition from Dockerfile                                                                 0.0s
 => => transferring dockerfile: 1.31kB                                                                               0.0s
 => [internal] load metadata for public.ecr.aws/lambda/python:3.13                                                   0.3s
 => [internal] load metadata for ghcr.io/astral-sh/uv:latest                                                         0.3s
 => [internal] load .dockerignore                                                                                    0.0s
 => => transferring context: 106B                                                                                    0.0s
 => [uv 1/1] FROM ghcr.io/astral-sh/uv:latest@sha256:ea61e006cfec0e8d81fae901ad703e09d2c6cf1aa58abcb6507d124b50286f  0.0s
 => [builder 1/2] FROM public.ecr.aws/lambda/python:3.13@sha256:f5b51b377b80bd303fe8055084e2763336ea8920d12955b23ef  0.0s
 => [internal] load build context                                                                                    0.0s
 => => transferring context: 185B                                                                                    0.0s
 => CACHED [builder 2/2] RUN --mount=from=uv,source=/uv,target=/bin/uv     --mount=type=cache,target=/root/.cache/u  0.0s
 => CACHED [stage-2 2/3] COPY --from=builder /var/task /var/task                                                     0.0s
 => CACHED [stage-2 3/3] COPY ./app /var/task                                                                        0.0s
 => exporting to image                                                                                               0.0s
 => => exporting layers                                                                                              0.0s
 => => writing image sha256:6f8f9ef715a7cda466b677a9df4046ebbb90c8e88595242ade3b4771f547652d                         0.0
```

After building, we can push the image to
[Elastic Container Registry (ECR)](https://aws.amazon.com/ecr/) with, e.g.:

```console
$ aws ecr get-login-password --region region | docker login --username AWS --password-stdin aws_account_id.dkr.ecr.region.amazonaws.com
$ docker tag fastapi-app:latest aws_account_id.dkr.ecr.region.amazonaws.com/fastapi-app:latest
$ docker push aws_account_id.dkr.ecr.region.amazonaws.com/fastapi-app:latest
```

Finally, we can deploy the image to AWS Lambda using the AWS Management Console or the AWS CLI,
e.g.:

```console
$ aws lambda create-function \
   --function-name myFunction \
   --package-type Image \
   --code ImageUri=aws_account_id.dkr.ecr.region.amazonaws.com/fastapi-app:latest \
   --role arn:aws:iam::111122223333:role/my-lambda-role
```

Where the
[execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html#permissions-executionrole-api)
is created via:

```console
$ aws iam create-role \
   --role-name my-lambda-role \
   --assume-role-policy-document '{"Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}'
```

Or, update an existing function with:

```console
$ aws lambda update-function-code \
   --function-name myFunction \
   --image-uri aws_account_id.dkr.ecr.region.amazonaws.com/fastapi-app:latest \
   --publish
```

To test the Lambda, we can invoke it via the AWS Management Console or the AWS CLI, e.g.:

```console
$ aws lambda invoke \
   --function-name myFunction \
   --payload file://event.json \
   --cli-binary-format raw-in-base64-out \
   response.json
{
  "StatusCode": 200,
  "ExecutedVersion": "$LATEST"
}
```

Where `event.json` contains the event payload to pass to the Lambda function:

```json title="event.json"
{
  "httpMethod": "GET",
  "path": "/",
  "requestContext": {},
  "version": "1.0"
}
```

And `response.json` contains the response from the Lambda function:

```json title="response.json"
{
  "statusCode": 200,
  "headers": {
    "content-length": "14",
    "content-type": "application/json"
  },
  "multiValueHeaders": {},
  "body": "\"Hello, world!\"",
  "isBase64Encoded": false
}
```

For details, see the
[AWS Lambda documentation](https://docs.aws.amazon.com/lambda/latest/dg/python-image.html).

### Workspace support

If a project includes local dependencies (e.g., via
[Workspaces](../../concepts/projects/workspaces.md)), those too must be included in the deployment
package.

We'll start by extending the above example to include a dependency on a locally-developed library
named `library`.

First, we'll create the library itself:

```console
$ uv init --lib library
$ uv add ./library
```

Running `uv init` within the `project` directory will automatically convert `project` to a workspace
and add `library` as a workspace member:

```toml title="pyproject.toml"
[project]
name = "uv-aws-lambda-example"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
    # FastAPI is a modern web framework for building APIs with Python.
    "fastapi",
    # A local library.
    "library",
    # Mangum is a library that adapts ASGI applications to AWS Lambda and API Gateway.
    "mangum",
]

[dependency-groups]
dev = [
    # In development mode, include the FastAPI development server.
    "fastapi[standard]",
]

[tool.uv.workspace]
members = ["library"]

[tool.uv.sources]
lib = { workspace = true }
```

By default, `uv init --lib` will create a package that exports a `hello` function. We'll modify the
application source code to call that function:

```python title="app/main.py"
import logging

from fastapi import FastAPI
from mangum import Mangum

from library import hello

logger = logging.getLogger()
logger.setLevel(logging.INFO)

app = FastAPI()
handler = Mangum(app)


@app.get("/")
async def root() -> str:
    return hello()
```

We can run the modified application locally with:

```console
$ uv run fastapi dev
```

And confirm that opening http://127.0.0.1:8000/ in a web browser displays, "Hello from library!"
(instead of "Hello, World!")

Finally, we'll update the Dockerfile to include the local library in the deployment package:

```dockerfile title="Dockerfile"
FROM ghcr.io/astral-sh/uv:0.8.22 AS uv

# First, bundle the dependencies into the task root.
FROM public.ecr.aws/lambda/python:3.13 AS builder

# Enable bytecode compilation, to improve cold-start performance.
ENV UV_COMPILE_BYTECODE=1

# Disable installer metadata, to create a deterministic layer.
ENV UV_NO_INSTALLER_METADATA=1

# Enable copy mode to support bind mount caching.
ENV UV_LINK_MODE=copy

# Bundle the dependencies into the Lambda task root via `uv pip install --target`.
#
# Omit any local packages (`--no-emit-workspace`) and development dependencies (`--no-dev`).
# This ensures that the Docker layer cache is only invalidated when the `pyproject.toml` or `uv.lock`
# files change, but remains robust to changes in the application code.
RUN --mount=from=uv,source=/uv,target=/bin/uv \
    --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    uv export --frozen --no-emit-workspace --no-dev --no-editable -o requirements.txt && \
    uv pip install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"

# If you have a workspace, copy it over and install it too.
#
# By omitting `--no-emit-workspace`, `library` will be copied into the task root. Using a separate
# `RUN` command ensures that all third-party dependencies are cached separately and remain
# robust to changes in the workspace.
RUN --mount=from=uv,source=/uv,target=/bin/uv \
    --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    --mount=type=bind,source=library,target=library \
    uv export --frozen --no-dev --no-editable -o requirements.txt && \
    uv pip install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"

FROM public.ecr.aws/lambda/python:3.13

# Copy the runtime dependencies from the builder stage.
COPY --from=builder ${LAMBDA_TASK_ROOT} ${LAMBDA_TASK_ROOT}

# Copy the application code.
COPY ./app ${LAMBDA_TASK_ROOT}/app

# Set the AWS Lambda handler.
CMD ["app.main.handler"]
```

!!! tip

    To deploy to ARM-based AWS Lambda runtimes, replace `public.ecr.aws/lambda/python:3.13` with `public.ecr.aws/lambda/python:3.13-arm64`.

From there, we can build and deploy the updated image as before.

## Deploying a zip archive

AWS Lambda also supports deployment via zip archives. For simple applications, zip archives can be a
more straightforward and efficient deployment method than Docker images; however, zip archives are
limited to
[250 MB](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html#python-package-create-update)
in size.

Returning to the FastAPI example, we can bundle the application dependencies into a local directory
for AWS Lambda via:

```console
$ uv export --frozen --no-dev --no-editable -o requirements.txt
$ uv pip install \
   --no-installer-metadata \
   --no-compile-bytecode \
   --python-platform x86_64-manylinux2014 \
   --python 3.13 \
   --target packages \
   -r requirements.txt
```

!!! tip

    To deploy to ARM-based AWS Lambda runtimes, replace `x86_64-manylinux2014` with `aarch64-manylinux2014`.

Following the
[AWS Lambda documentation](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html), we can
then bundle these dependencies into a zip as follows:

```console
$ cd packages
$ zip -r ../package.zip .
$ cd ..
```

Finally, we can add the application code to the zip archive:

```console
$ zip -r package.zip app
```

We can then deploy the zip archive to AWS Lambda via the AWS Management Console or the AWS CLI,
e.g.:

```console
$ aws lambda create-function \
   --function-name myFunction \
   --runtime python3.13 \
   --zip-file fileb://package.zip \
   --handler app.main.handler \
   --role arn:aws:iam::111122223333:role/service-role/my-lambda-role
```

Where the
[execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html#permissions-executionrole-api)
is created via:

```console
$ aws iam create-role \
   --role-name my-lambda-role \
   --assume-role-policy-document '{"Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}'
```

Or, update an existing function with:

```console
$ aws lambda update-function-code \
   --function-name myFunction \
   --zip-file fileb://package.zip
```

!!! note

    By default, the AWS Management Console assumes a Lambda entrypoint of `lambda_function.lambda_handler`.
    If your application uses a different entrypoint, you'll need to modify it in the AWS Management Console.
    For example, the above FastAPI application uses `app.main.handler`.

To test the Lambda, we can invoke it via the AWS Management Console or the AWS CLI, e.g.:

```console
$ aws lambda invoke \
   --function-name myFunction \
   --payload file://event.json \
   --cli-binary-format raw-in-base64-out \
   response.json
{
  "StatusCode": 200,
  "ExecutedVersion": "$LATEST"
}
```

Where `event.json` contains the event payload to pass to the Lambda function:

```json title="event.json"
{
  "httpMethod": "GET",
  "path": "/",
  "requestContext": {},
  "version": "1.0"
}
```

And `response.json` contains the response from the Lambda function:

```json title="response.json"
{
  "statusCode": 200,
  "headers": {
    "content-length": "14",
    "content-type": "application/json"
  },
  "multiValueHeaders": {},
  "body": "\"Hello, world!\"",
  "isBase64Encoded": false
}
```

### Using a Lambda layer

AWS Lambda also supports the deployment of multiple composed
[Lambda layers](https://docs.aws.amazon.com/lambda/latest/dg/python-layers.html) when working with
zip archives. These layers are conceptually similar to layers in a Docker image, allowing you to
separate application code from dependencies.

In particular, we can create a lambda layer for application dependencies and attach it to the Lambda
function, separate from the application code itself. This setup can improve cold-start performance
for application updates, as the dependencies layer can be reused across deployments.

To create a Lambda layer, we'll follow similar steps, but create two separate zip archives: one for
the application code and one for the application dependencies.

First, we'll create the dependency layer. Lambda layers are expected to follow a slightly different
structure, so we'll use `--prefix` rather than `--target`:

```console
$ uv export --frozen --no-dev --no-editable -o requirements.txt
$ uv pip install \
   --no-installer-metadata \
   --no-compile-bytecode \
   --python-platform x86_64-manylinux2014 \
   --python 3.13 \
   --prefix packages \
   -r requirements.txt
```

We'll then zip the dependencies in adherence with the expected layout for Lambda layers:

```console
$ mkdir python
$ cp -r packages/lib python/
$ zip -r layer_content.zip python
```

!!! tip

    To generate deterministic zip archives, consider passing the `-X` flag to `zip` to exclude
    extended attributes and file system metadata.

And publish the Lambda layer:

```console
$ aws lambda publish-layer-version --layer-name dependencies-layer \
   --zip-file fileb://layer_content.zip \
   --compatible-runtimes python3.13 \
   --compatible-architectures "x86_64"
```

We can then create the Lambda function as in the previous example, omitting the dependencies:

```console
$ # Zip the application code.
$ zip -r app.zip app

$ # Create the Lambda function.
$ aws lambda create-function \
   --function-name myFunction \
   --runtime python3.13 \
   --zip-file fileb://app.zip \
   --handler app.main.handler \
   --role arn:aws:iam::111122223333:role/service-role/my-lambda-role
```

Finally, we can attach the dependencies layer to the Lambda function, using the ARN returned by the
`publish-layer-version` step:

```console
$ aws lambda update-function-configuration --function-name myFunction \
    --cli-binary-format raw-in-base64-out \
    --layers "arn:aws:lambda:region:111122223333:layer:dependencies-layer:1"
```

When the application dependencies change, the layer can be updated independently of the application
by republishing the layer and updating the Lambda function configuration:

```console
$ # Update the dependencies in the layer.
$ aws lambda publish-layer-version --layer-name dependencies-layer \
   --zip-file fileb://layer_content.zip \
   --compatible-runtimes python3.13 \
   --compatible-architectures "x86_64"

$ # Update the Lambda function configuration.
$ aws lambda update-function-configuration --function-name myFunction \
    --cli-binary-format raw-in-base64-out \
    --layers "arn:aws:lambda:region:111122223333:layer:dependencies-layer:2"
```

    ---
title: Using uv with Coiled
description:
  A complete guide to using uv with Coiled to manage Python dependencies and deploy serverless
  scripts.
---

# Using uv with Coiled

[Coiled](https://coiled.io?utm_source=uv-docs) is a serverless, UX-focused cloud computing platform
that makes it easy to run code on cloud hardware (AWS, GCP, and Azure).

This guide shows how to run Python scripts on the cloud using uv for dependency management and
Coiled for cloud deployment.

## Managing script dependencies with uv

!!! note

    We'll use this concrete example throughout this guide, but any Python script can be used with
    uv and Coiled.

We'll use the following script as an example:

```python title="process.py" hl_lines="1-8"
# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "pandas",
#   "pyarrow",
#   "s3fs",
# ]
# ///

import pandas as pd

df = pd.read_parquet(
    "s3://coiled-data/uber/part.0.parquet",
    storage_options={"anon": True},
)
print(df.head())
```

The script uses [`pandas`](https://pandas.pydata.org/docs/) to load a Parquet file hosted in a
public bucket on S3, then prints the first few rows. It uses
[inline script metadata](https://peps.python.org/pep-0723/) to enumerate its dependencies.

When running this script locally, e.g., with:

```bash
$ uv run process.py
```

uv will automatically create a virtual environment and installs its dependencies.

To learn more about using inline script metadata with uv, see the
[script guide](../scripts.md#declaring-script-dependencies).

## Running scripts on the cloud with Coiled

Using inline script metadata makes the script fully self-contained: it includes the information that
is needed to run it. This makes it easier to run on other machines, like a machine in the cloud.

There are many use cases where resources beyond what's available on a local workstation are needed,
e.g.:

- Processing large amounts of cloud-hosted data
- Needing accelerated hardware like GPUs or a big machine with more memory
- Running the same script with hundreds or thousands of different inputs, in parallel

Coiled makes it simple to run code on cloud hardware.

First, authenticate with Coiled using
[`coiled login`](https://docs.coiled.io/user_guide/api.html?utm_source=uv-docs#coiled-login) :

```bash
$ uvx coiled login
```

You'll be prompted to create a Coiled account if you don't already have one — it's free to start
using Coiled.

To instruct Coiled to run the script on a virtual machine on AWS, add two comments to the top:

```python title="process.py" hl_lines="1-2"
# COILED container ghcr.io/astral-sh/uv:debian-slim
# COILED region us-east-2

# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "pandas",
#   "pyarrow",
#   "s3fs",
# ]
# ///

import pandas as pd

df = pd.read_parquet(
    "s3://coiled-data/uber/part.0.parquet",
    storage_options={"anon": True},
)
print(df.head())
```

!!! tip

    While Coiled supports AWS, GCP, and Azure, this example assumes AWS is being used
    (see the `region` option above). If you're new to Coiled, you'll automatically have
    access to a free account running on AWS. If you're not running on AWS, you can either use
    a valid `region` for your cloud provider or remove the `region` line above.

The comments tell Coiled to use the official [uv Docker image](../integration/docker.md) when
running the script (ensuring uv is available) and to run in the `us-east-2` region on AWS (where
this example data file happens to live) to avoid any data egress.

To submit a batch job for Coiled to run, use
[`coiled batch run`](https://docs.coiled.io/user_guide/api.html?utm_source=uv-docs#coiled-batch-run)
to execute the `uv run` command in the cloud:

```bash hl_lines="1"
$ uvx coiled batch run \
    uv run process.py
```

The same process that previously ran locally is now running on a remote cloud VM on AWS.

You can monitor the progress of the batch job in the UI at
[cloud.coiled.io](https://cloud.coiled.io) or from the terminal using the `coiled batch status`,
`coiled batch wait`, and `coiled batch logs` commands.

![Coiled UI](https://docs.coiled.io/_images/uv-coiled.png)

Note there's additional configuration we could have specified, e.g., the instance type (the default
is a 4-core virtual machine with 16 GiB of memory), disk size, whether to use spot instance, and
more. See the
[Coiled Batch documentation](https://docs.coiled.io/user_guide/batch.html?utm_source=uv-docs) for
more details.

For more details on Coiled, and how it can help with other use cases, see the
[Coiled documentation](https://docs.coiled.io?utm_source=uv-docs).

    ---
title: Using uv with dependency bots
description: A guide to using uv with dependency bots like Renovate and Dependabot.
---

# Dependency bots

It is considered best practice to regularly update dependencies, to avoid being exposed to
vulnerabilities, limit incompatibilities between dependencies, and avoid complex upgrades when
upgrading from a too old version. A variety of tools can help staying up-to-date by creating
automated pull requests. Several of them support uv, or have work underway to support it.

## Renovate

uv is supported by [Renovate](https://github.com/renovatebot/renovate).

### `uv.lock` output

Renovate uses the presence of a `uv.lock` file to determine that uv is used for managing
dependencies, and will suggest upgrades to
[project dependencies](../../concepts/projects/dependencies.md#project-dependencies),
[optional dependencies](../../concepts/projects/dependencies.md#optional-dependencies) and
[development dependencies](../../concepts/projects/dependencies.md#development-dependencies).
Renovate will update both the `pyproject.toml` and `uv.lock` files.

The lockfile can also be refreshed on a regular basis (for instance to update transitive
dependencies) by enabling the
[`lockFileMaintenance`](https://docs.renovatebot.com/configuration-options/#lockfilemaintenance)
option:

```jsx title="renovate.json5"
{
  $schema: "https://docs.renovatebot.com/renovate-schema.json",
  lockFileMaintenance: {
    enabled: true,
  },
}
```

### Inline script metadata

Renovate supports updating dependencies defined using
[script inline metadata](../scripts.md/#declaring-script-dependencies).

Since it cannot automatically detect which Python files use script inline metadata, their locations
need to be explicitly defined using
[`fileMatch`](https://docs.renovatebot.com/configuration-options/#filematch), like so:

```jsx title="renovate.json5"
{
  $schema: "https://docs.renovatebot.com/renovate-schema.json",
  pep723: {
    fileMatch: [
      "scripts/generate_docs\\.py",
      "scripts/run_server\\.py",
    ],
  },
}
```

## Dependabot

Dependabot has announced support for uv, but there are some use cases that are not yet working. See
[astral-sh/uv#2512](https://github.com/astral-sh/uv/issues/2512) for updates.

Dependabot supports updating `uv.lock` files. To enable it, add the uv `package-ecosystem` to your
`updates` list in the `dependabot.yml`:

```yaml title="dependabot.yml"
version: 2

updates:
  - package-ecosystem: "uv"
    directory: "/"
    schedule:
      interval: "weekly"
```

    ---
title: Using uv in Docker
description:
  A complete guide to using uv in Docker to manage Python dependencies while optimizing build times
  and image size via multi-stage builds, intermediate layers, and more.
---

# Using uv in Docker

## Getting started

!!! tip

    Check out the [`uv-docker-example`](https://github.com/astral-sh/uv-docker-example) project for
    an example of best practices when using uv to build an application in Docker.

uv provides both _distroless_ Docker images, which are useful for
[copying uv binaries](#installing-uv) into your own image builds, and images derived from popular
base images, which are useful for using uv in a container. The distroless images do not contain
anything but the uv binaries. In contrast, the derived images include an operating system with uv
pre-installed.

As an example, to run uv in a container using a Debian-based image:

```console
$ docker run --rm -it ghcr.io/astral-sh/uv:debian uv --help
```

### Available images

The following distroless images are available:

- `ghcr.io/astral-sh/uv:latest`
- `ghcr.io/astral-sh/uv:{major}.{minor}.{patch}`, e.g., `ghcr.io/astral-sh/uv:0.8.22`
- `ghcr.io/astral-sh/uv:{major}.{minor}`, e.g., `ghcr.io/astral-sh/uv:0.8` (the latest patch
  version)

And the following derived images are available:

<!-- prettier-ignore -->
- Based on `alpine:3.21`:
    - `ghcr.io/astral-sh/uv:alpine`
    - `ghcr.io/astral-sh/uv:alpine3.21`
- Based on `alpine:3.22`:
    - `ghcr.io/astral-sh/uv:alpine3.22`
- Based on `debian:bookworm-slim`:
    - `ghcr.io/astral-sh/uv:debian-slim`
    - `ghcr.io/astral-sh/uv:bookworm-slim`
- Based on `debian:trixie-slim`:
    - `ghcr.io/astral-sh/uv:trixie-slim`
- Based on `buildpack-deps:bookworm`:
    - `ghcr.io/astral-sh/uv:debian`
    - `ghcr.io/astral-sh/uv:bookworm`
- Based on `buildpack-deps:trixie`:
    - `ghcr.io/astral-sh/uv:trixie`
- Based on `python3.x-alpine`:
    - `ghcr.io/astral-sh/uv:python3.14-rc-alpine`
    - `ghcr.io/astral-sh/uv:python3.13-alpine`
    - `ghcr.io/astral-sh/uv:python3.12-alpine`
    - `ghcr.io/astral-sh/uv:python3.11-alpine`
    - `ghcr.io/astral-sh/uv:python3.10-alpine`
    - `ghcr.io/astral-sh/uv:python3.9-alpine`
    - `ghcr.io/astral-sh/uv:python3.8-alpine`
- Based on `python3.x-bookworm`:
    - `ghcr.io/astral-sh/uv:python3.14-rc-bookworm`
    - `ghcr.io/astral-sh/uv:python3.13-bookworm`
    - `ghcr.io/astral-sh/uv:python3.12-bookworm`
    - `ghcr.io/astral-sh/uv:python3.11-bookworm`
    - `ghcr.io/astral-sh/uv:python3.10-bookworm`
    - `ghcr.io/astral-sh/uv:python3.9-bookworm`
    - `ghcr.io/astral-sh/uv:python3.8-bookworm`
- Based on `python3.x-slim-bookworm`:
    - `ghcr.io/astral-sh/uv:python3.14-rc-bookworm-slim`
    - `ghcr.io/astral-sh/uv:python3.13-bookworm-slim`
    - `ghcr.io/astral-sh/uv:python3.12-bookworm-slim`
    - `ghcr.io/astral-sh/uv:python3.11-bookworm-slim`
    - `ghcr.io/astral-sh/uv:python3.10-bookworm-slim`
    - `ghcr.io/astral-sh/uv:python3.9-bookworm-slim`
    - `ghcr.io/astral-sh/uv:python3.8-bookworm-slim`
- Based on `python3.x-trixie`:
    - `ghcr.io/astral-sh/uv:python3.14-rc-trixie`
    - `ghcr.io/astral-sh/uv:python3.13-trixie`
    - `ghcr.io/astral-sh/uv:python3.12-trixie`
    - `ghcr.io/astral-sh/uv:python3.11-trixie`
    - `ghcr.io/astral-sh/uv:python3.10-trixie`
    - `ghcr.io/astral-sh/uv:python3.9-trixie`
- Based on `python3.x-slim-trixie`:
    - `ghcr.io/astral-sh/uv:python3.14-rc-trixie-slim`
    - `ghcr.io/astral-sh/uv:python3.13-trixie-slim`
    - `ghcr.io/astral-sh/uv:python3.12-trixie-slim`
    - `ghcr.io/astral-sh/uv:python3.11-trixie-slim`
    - `ghcr.io/astral-sh/uv:python3.10-trixie-slim`
    - `ghcr.io/astral-sh/uv:python3.9-trixie-slim`
<!-- prettier-ignore-end -->

As with the distroless image, each derived image is published with uv version tags as
`ghcr.io/astral-sh/uv:{major}.{minor}.{patch}-{base}` and
`ghcr.io/astral-sh/uv:{major}.{minor}-{base}`, e.g., `ghcr.io/astral-sh/uv:0.8.22-alpine`.

In addition, starting with `0.8` each derived image also sets `UV_TOOL_BIN_DIR` to `/usr/local/bin`
to allow `uv tool install` to work as expected with the default user.

For more details, see the [GitHub Container](https://github.com/astral-sh/uv/pkgs/container/uv)
page.

### Installing uv

Use one of the above images with uv pre-installed or install uv by copying the binary from the
official distroless Docker image:

```dockerfile title="Dockerfile"
FROM python:3.12-slim-trixie
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
```

Or, with the installer:

```dockerfile title="Dockerfile"
FROM python:3.12-slim-trixie

# The installer requires curl (and certificates) to download the release archive
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates

# Download the latest installer
ADD https://astral.sh/uv/install.sh /uv-installer.sh

# Run the installer then remove it
RUN sh /uv-installer.sh && rm /uv-installer.sh

# Ensure the installed binary is on the `PATH`
ENV PATH="/root/.local/bin/:$PATH"
```

Note this requires `curl` to be available.

In either case, it is best practice to pin to a specific uv version, e.g., with:

```dockerfile
COPY --from=ghcr.io/astral-sh/uv:0.8.22 /uv /uvx /bin/
```

!!! tip

    While the Dockerfile example above pins to a specific tag, it's also
    possible to pin a specific SHA256. Pinning a specific SHA256 is considered
    best practice in environments that require reproducible builds as tags can
    be moved across different commit SHAs.

    ```Dockerfile
    # e.g., using a hash from a previous release
    COPY --from=ghcr.io/astral-sh/uv@sha256:2381d6aa60c326b71fd40023f921a0a3b8f91b14d5db6b90402e65a635053709 /uv /uvx /bin/
    ```

Or, with the installer:

```dockerfile
ADD https://astral.sh/uv/0.8.22/install.sh /uv-installer.sh
```

### Installing a project

If you're using uv to manage your project, you can copy it into the image and install it:

```dockerfile title="Dockerfile"
# Copy the project into the image
ADD . /app

# Sync the project into a new environment, asserting the lockfile is up to date
WORKDIR /app
RUN uv sync --locked
```

!!! important

    It is best practice to add `.venv` to a [`.dockerignore` file](https://docs.docker.com/build/concepts/context/#dockerignore-files)
    in your repository to prevent it from being included in image builds. The project virtual
    environment is dependent on your local platform and should be created from scratch in the image.

Then, to start your application by default:

```dockerfile title="Dockerfile"
# Presuming there is a `my_app` command provided by the project
CMD ["uv", "run", "my_app"]
```

!!! tip

    It is best practice to use [intermediate layers](#intermediate-layers) separating installation
    of dependencies and the project itself to improve Docker image build times.

See a complete example in the
[`uv-docker-example` project](https://github.com/astral-sh/uv-docker-example/blob/main/Dockerfile).

### Using the environment

Once the project is installed, you can either _activate_ the project virtual environment by placing
its binary directory at the front of the path:

```dockerfile title="Dockerfile"
ENV PATH="/app/.venv/bin:$PATH"
```

Or, you can use `uv run` for any commands that require the environment:

```dockerfile title="Dockerfile"
RUN uv run some_script.py
```

!!! tip

    Alternatively, the
    [`UV_PROJECT_ENVIRONMENT` setting](../../concepts/projects/config.md#project-environment-path) can
    be set before syncing to install to the system Python environment and skip environment activation
    entirely.

### Using installed tools

To use installed tools, ensure the [tool bin directory](../../concepts/tools.md#the-bin-directory)
is on the path:

```dockerfile title="Dockerfile"
ENV PATH=/root/.local/bin:$PATH
RUN uv tool install cowsay
```

```console
$ docker run -it $(docker build -q .) /bin/bash -c "cowsay -t hello"
  _____
| hello |
  =====
     \
      \
        ^__^
        (oo)\_______
        (__)\       )\/\
            ||----w |
            ||     ||
```

!!! note

    The tool bin directory's location can be determined by running the `uv tool dir --bin` command
    in the container.

    Alternatively, it can be set to a constant location:

    ```dockerfile title="Dockerfile"
    ENV UV_TOOL_BIN_DIR=/opt/uv-bin/
    ```

### Installing Python in ARM musl images

While uv will attempt to [install a compatible Python version](../install-python.md) if no such
version is available in the image, uv does not yet support installing Python for musl Linux on ARM.
For example, if you are using an Alpine Linux base image on an ARM machine, you may need to add it
with the system package manager:

```shell
apk add --no-cache python3~=3.12
```

## Developing in a container

When developing, it's useful to mount the project directory into a container. With this setup,
changes to the project can be immediately reflected in a containerized service without rebuilding
the image. However, it is important _not_ to include the project virtual environment (`.venv`) in
the mount, because the virtual environment is platform specific and the one built for the image
should be kept.

### Mounting the project with `docker run`

Bind mount the project (in the working directory) to `/app` while retaining the `.venv` directory
with an [anonymous volume](https://docs.docker.com/engine/storage/#volumes):

```console
$ docker run --rm --volume .:/app --volume /app/.venv [...]
```

!!! tip

    The `--rm` flag is included to ensure the container and anonymous volume are cleaned up when the
    container exits.

See a complete example in the
[`uv-docker-example` project](https://github.com/astral-sh/uv-docker-example/blob/main/run.sh).

### Configuring `watch` with `docker compose`

When using Docker compose, more sophisticated tooling is available for container development. The
[`watch`](https://docs.docker.com/compose/file-watch/#compose-watch-versus-bind-mounts) option
allows for greater granularity than is practical with a bind mount and supports triggering updates
to the containerized service when files change.

!!! note

    This feature requires Compose 2.22.0 which is bundled with Docker Desktop 4.24.

Configure `watch` in your
[Docker compose file](https://docs.docker.com/compose/compose-application-model/#the-compose-file)
to mount the project directory without syncing the project virtual environment and to rebuild the
image when the configuration changes:

```yaml title="compose.yaml"
services:
  example:
    build: .

    # ...

    develop:
      # Create a `watch` configuration to update the app
      #
      watch:
        # Sync the working directory with the `/app` directory in the container
        - action: sync
          path: .
          target: /app
          # Exclude the project virtual environment
          ignore:
            - .venv/

        # Rebuild the image on changes to the `pyproject.toml`
        - action: rebuild
          path: ./pyproject.toml
```

Then, run `docker compose watch` to run the container with the development setup.

See a complete example in the
[`uv-docker-example` project](https://github.com/astral-sh/uv-docker-example/blob/main/compose.yml).

## Optimizations

### Compiling bytecode

Compiling Python source files to bytecode is typically desirable for production images as it tends
to improve startup time (at the cost of increased installation time).

To enable bytecode compilation, use the `--compile-bytecode` flag:

```dockerfile title="Dockerfile"
RUN uv sync --compile-bytecode
```

Alternatively, you can set the `UV_COMPILE_BYTECODE` environment variable to ensure that all
commands within the Dockerfile compile bytecode:

```dockerfile title="Dockerfile"
ENV UV_COMPILE_BYTECODE=1
```

### Caching

A [cache mount](https://docs.docker.com/build/guide/mounts/#add-a-cache-mount) can be used to
improve performance across builds:

```dockerfile title="Dockerfile"
ENV UV_LINK_MODE=copy

RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync
```

Changing the default [`UV_LINK_MODE`](../../reference/settings.md#link-mode) silences warnings about
not being able to use hard links since the cache and sync target are on separate file systems.

If you're not mounting the cache, image size can be reduced by using the `--no-cache` flag or
setting `UV_NO_CACHE`.

By default, managed Python installations are not cached before being installed. Setting
`UV_PYTHON_CACHE_DIR` can be used in combination with a cache mount:

```dockerfile title="Dockerfile"
ENV UV_PYTHON_CACHE_DIR=/root/.cache/uv/python

RUN --mount=type=cache,target=/root/.cache/uv \
    uv python install
```

!!! note

    The cache directory's location can be determined by running the `uv cache dir` command in the
    container.

    Alternatively, the cache can be set to a constant location:

    ```dockerfile title="Dockerfile"
    ENV UV_CACHE_DIR=/opt/uv-cache/
    ```

### Intermediate layers

If you're using uv to manage your project, you can improve build times by moving your transitive
dependency installation into its own layer via the `--no-install` options.

`uv sync --no-install-project` will install the dependencies of the project but not the project
itself. Since the project changes frequently, but its dependencies are generally static, this can be
a big time saver.

```dockerfile title="Dockerfile"
# Install uv
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# Change the working directory to the `app` directory
WORKDIR /app

# Install dependencies
RUN --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    uv sync --locked --no-install-project

# Copy the project into the image
ADD . /app

# Sync the project
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --locked
```

Note that the `pyproject.toml` is required to identify the project root and name, but the project
_contents_ are not copied into the image until the final `uv sync` command.

!!! tip

    If you're using a [workspace](../../concepts/projects/workspaces.md), then use the
    `--no-install-workspace` flag which excludes the project _and_ any workspace members.

    If you want to remove specific packages from the sync, use `--no-install-package <name>`.

### Non-editable installs

By default, uv installs projects and workspace members in editable mode, such that changes to the
source code are immediately reflected in the environment.

`uv sync` and `uv run` both accept a `--no-editable` flag, which instructs uv to install the project
in non-editable mode, removing any dependency on the source code.

In the context of a multi-stage Docker image, `--no-editable` can be used to include the project in
the synced virtual environment from one stage, then copy the virtual environment alone (and not the
source code) into the final image.

For example:

```dockerfile title="Dockerfile"
# Install uv
FROM python:3.12-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# Change the working directory to the `app` directory
WORKDIR /app

# Install dependencies
RUN --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    uv sync --locked --no-install-project --no-editable

# Copy the project into the intermediate image
ADD . /app

# Sync the project
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --locked --no-editable

FROM python:3.12-slim

# Copy the environment, but not the source code
COPY --from=builder --chown=app:app /app/.venv /app/.venv

# Run the application
CMD ["/app/.venv/bin/hello"]
```

### Using uv temporarily

If uv isn't needed in the final image, the binary can be mounted in each invocation:

```dockerfile title="Dockerfile"
RUN --mount=from=ghcr.io/astral-sh/uv,source=/uv,target=/bin/uv \
    uv sync
```

## Using the pip interface

### Installing a package

The system Python environment is safe to use this context, since a container is already isolated.
The `--system` flag can be used to install in the system environment:

```dockerfile title="Dockerfile"
RUN uv pip install --system ruff
```

To use the system Python environment by default, set the `UV_SYSTEM_PYTHON` variable:

```dockerfile title="Dockerfile"
ENV UV_SYSTEM_PYTHON=1
```

Alternatively, a virtual environment can be created and activated:

```dockerfile title="Dockerfile"
RUN uv venv /opt/venv
# Use the virtual environment automatically
ENV VIRTUAL_ENV=/opt/venv
# Place entry points in the environment at the front of the path
ENV PATH="/opt/venv/bin:$PATH"
```

When using a virtual environment, the `--system` flag should be omitted from uv invocations:

```dockerfile title="Dockerfile"
RUN uv pip install ruff
```

### Installing requirements

To install requirements files, copy them into the container:

```dockerfile title="Dockerfile"
COPY requirements.txt .
RUN uv pip install -r requirements.txt
```

### Installing a project

When installing a project alongside requirements, it is best practice to separate copying the
requirements from the rest of the source code. This allows the dependencies of the project (which do
not change often) to be cached separately from the project itself (which changes very frequently).

```dockerfile title="Dockerfile"
COPY pyproject.toml .
RUN uv pip install -r pyproject.toml
COPY . .
RUN uv pip install -e .
```

## Verifying image provenance

The Docker images are signed during the build process to provide proof of their origin. These
attestations can be used to verify that an image was produced from an official channel.

For example, you can verify the attestations with the
[GitHub CLI tool `gh`](https://cli.github.com/):

```console
$ gh attestation verify --owner astral-sh oci://ghcr.io/astral-sh/uv:latest
Loaded digest sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx for oci://ghcr.io/astral-sh/uv:latest
Loaded 1 attestation from GitHub API

The following policy criteria will be enforced:
- OIDC Issuer must match:................... https://token.actions.githubusercontent.com
- Source Repository Owner URI must match:... https://github.com/astral-sh
- Predicate type must match:................ https://slsa.dev/provenance/v1
- Subject Alternative Name must match regex: (?i)^https://github.com/astral-sh/

✓ Verification succeeded!

sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx was attested by:
REPO          PREDICATE_TYPE                  WORKFLOW
astral-sh/uv  https://slsa.dev/provenance/v1  .github/workflows/build-docker.yml@refs/heads/main
```

This tells you that the specific Docker image was built by the official uv GitHub release workflow
and hasn't been tampered with since.

GitHub attestations build on the [sigstore.dev infrastructure](https://www.sigstore.dev/). As such
you can also use the [`cosign` command](https://github.com/sigstore/cosign) to verify the
attestation blob against the (multi-platform) manifest for `uv`:

```console
$ REPO=astral-sh/uv
$ gh attestation download --repo $REPO oci://ghcr.io/${REPO}:latest
Wrote attestations to file sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.jsonl.
Any previous content has been overwritten

The trusted metadata is now available at sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.jsonl
$ docker buildx imagetools inspect ghcr.io/${REPO}:latest --format "{{json .Manifest}}" > manifest.json
$ cosign verify-blob-attestation \
    --new-bundle-format \
    --bundle "$(jq -r .digest manifest.json).jsonl"  \
    --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
    --certificate-identity-regexp="^https://github\.com/${REPO}/.*" \
    <(jq -j '.|del(.digest,.size)' manifest.json)
Verified OK
```

!!! tip

    These examples use `latest`, but best practice is to verify the attestation for a specific
    version tag, e.g., `ghcr.io/astral-sh/uv:0.8.22`, or (even better) the specific image digest,
    such as `ghcr.io/astral-sh/uv:0.5.27@sha256:5adf09a5a526f380237408032a9308000d14d5947eafa687ad6c6a2476787b4f`.

    ---
title: Using uv with FastAPI
description:
  A guide to using uv with FastAPI to manage Python dependencies, run applications, and deploy with
  Docker.
---

# Using uv with FastAPI

[FastAPI](https://github.com/fastapi/fastapi) is a modern, high-performance Python web framework.
You can use uv to manage your FastAPI project, including installing dependencies, managing
environments, running FastAPI applications, and more.

!!! note

    You can view the source code for this guide in the [uv-fastapi-example](https://github.com/astral-sh/uv-fastapi-example) repository.

## Migrating an existing FastAPI project

As an example, consider the sample application defined in the
[FastAPI documentation](https://fastapi.tiangolo.com/tutorial/bigger-applications/), structured as
follows:

```plaintext
project
└── app
    ├── __init__.py
    ├── main.py
    ├── dependencies.py
    ├── routers
    │   ├── __init__.py
    │   ├── items.py
    │   └── users.py
    └── internal
        ├── __init__.py
        └── admin.py
```

To use uv with this application, inside the `project` directory run:

```console
$ uv init --app
```

This creates a [project with an application layout](../../concepts/projects/init.md#applications)
and a `pyproject.toml` file.

Then, add a dependency on FastAPI:

```console
$ uv add fastapi --extra standard
```

You should now have the following structure:

```plaintext
project
├── pyproject.toml
└── app
    ├── __init__.py
    ├── main.py
    ├── dependencies.py
    ├── routers
    │   ├── __init__.py
    │   ├── items.py
    │   └── users.py
    └── internal
        ├── __init__.py
        └── admin.py
```

And the contents of the `pyproject.toml` file should look something like this:

```toml title="pyproject.toml"
[project]
name = "uv-fastapi-example"
version = "0.1.0"
description = "FastAPI project"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "fastapi[standard]",
]
```

From there, you can run the FastAPI application with:

```console
$ uv run fastapi dev
```

`uv run` will automatically resolve and lock the project dependencies (i.e., create a `uv.lock`
alongside the `pyproject.toml`), create a virtual environment, and run the command in that
environment.

Test the app by opening http://127.0.0.1:8000/?token=jessica in a web browser.

## Deployment

To deploy the FastAPI application with Docker, you can use the following `Dockerfile`:

```dockerfile title="Dockerfile"
FROM python:3.12-slim

# Install uv.
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# Copy the application into the container.
COPY . /app

# Install the application dependencies.
WORKDIR /app
RUN uv sync --frozen --no-cache

# Run the application.
CMD ["/app/.venv/bin/fastapi", "run", "app/main.py", "--port", "80", "--host", "0.0.0.0"]
```

Build the Docker image with:

```console
$ docker build -t fastapi-app .
```

Run the Docker container locally with:

```console
$ docker run -p 8000:80 fastapi-app
```

Navigate to http://127.0.0.1:8000/?token=jessica in your browser to verify that the app is running
correctly.

!!! tip

    For more on using uv with Docker, see the [Docker guide](./docker.md).

    ---
title: Using uv in GitHub Actions
description:
  A guide to using uv in GitHub Actions, including installation, setting up Python, installing
  dependencies, and more.
---

# Using uv in GitHub Actions

## Installation

For use with GitHub Actions, we recommend the official
[`astral-sh/setup-uv`](https://github.com/astral-sh/setup-uv) action, which installs uv, adds it to
PATH, (optionally) persists the cache, and more, with support for all uv-supported platforms.

To install the latest version of uv:

```yaml title="example.yml" hl_lines="11 12"
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v5

      - name: Install uv
        uses: astral-sh/setup-uv@v6
```

It is considered best practice to pin to a specific uv version, e.g., with:

```yaml title="example.yml" hl_lines="14 15"
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v5

      - name: Install uv
        uses: astral-sh/setup-uv@v6
        with:
          # Install a specific version of uv.
          version: "0.8.22"
```

## Setting up Python

Python can be installed with the `python install` command:

```yaml title="example.yml" hl_lines="14 15"
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v5

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

      - name: Set up Python
        run: uv python install
```

This will respect the Python version pinned in the project.

Alternatively, the official GitHub `setup-python` action can be used. This can be faster, because
GitHub caches the Python versions alongside the runner.

Set the
[`python-version-file`](https://github.com/actions/setup-python/blob/main/docs/advanced-usage.md#using-the-python-version-file-input)
option to use the pinned version for the project:

```yaml title="example.yml" hl_lines="14"
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v5

      - name: "Set up Python"
        uses: actions/setup-python@v5
        with:
          python-version-file: ".python-version"

      - name: Install uv
        uses: astral-sh/setup-uv@v6
```

Or, specify the `pyproject.toml` file to ignore the pin and use the latest version compatible with
the project's `requires-python` constraint:

```yaml title="example.yml" hl_lines="14"
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v5

      - name: "Set up Python"
        uses: actions/setup-python@v5
        with:
          python-version-file: "pyproject.toml"

      - name: Install uv
        uses: astral-sh/setup-uv@v6
```

## Multiple Python versions

When using a matrix to test multiple Python versions, set the Python version using
`astral-sh/setup-uv`, which will override the Python version specification in the `pyproject.toml`
or `.python-version` files:

```yaml title="example.yml" hl_lines="17 18"
jobs:
  build:
    name: continuous-integration
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version:
          - "3.10"
          - "3.11"
          - "3.12"

    steps:
      - uses: actions/checkout@v5

      - name: Install uv and set the Python version
        uses: astral-sh/setup-uv@v6
        with:
          python-version: ${{ matrix.python-version }}
```

If not using the `setup-uv` action, you can set the `UV_PYTHON` environment variable:

```yaml title="example.yml" hl_lines="12"
jobs:
  build:
    name: continuous-integration
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version:
          - "3.10"
          - "3.11"
          - "3.12"
    env:
      UV_PYTHON: ${{ matrix.python-version }}
    steps:
      - uses: actions/checkout@v5
```

## Syncing and running

Once uv and Python are installed, the project can be installed with `uv sync` and commands can be
run in the environment with `uv run`:

```yaml title="example.yml" hl_lines="15 17-22"
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v5

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

      - name: Install the project
        run: uv sync --locked --all-extras --dev

      - name: Run tests
        # For example, using `pytest`
        run: uv run pytest tests
```

!!! tip

    The
    [`UV_PROJECT_ENVIRONMENT` setting](../../concepts/projects/config.md#project-environment-path) can
    be used to install to the system Python environment instead of creating a virtual environment.

## Caching

It may improve CI times to store uv's cache across workflow runs.

The [`astral-sh/setup-uv`](https://github.com/astral-sh/setup-uv) has built-in support for
persisting the cache:

```yaml title="example.yml"
- name: Enable caching
  uses: astral-sh/setup-uv@v6
  with:
    enable-cache: true
```

Alternatively, you can manage the cache manually with the `actions/cache` action:

```yaml title="example.yml"
jobs:
  install_job:
    env:
      # Configure a constant location for the uv cache
      UV_CACHE_DIR: /tmp/.uv-cache

    steps:
      # ... setup up Python and uv ...

      - name: Restore uv cache
        uses: actions/cache@v4
        with:
          path: /tmp/.uv-cache
          key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
          restore-keys: |
            uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
            uv-${{ runner.os }}

      # ... install packages, run tests, etc ...

      - name: Minimize uv cache
        run: uv cache prune --ci
```

The `uv cache prune --ci` command is used to reduce the size of the cache and is optimized for CI.
Its effect on performance is dependent on the packages being installed.

!!! tip

    If using `uv pip`, use `requirements.txt` instead of `uv.lock` in the cache key.

!!! note

    [post-job-hook]: https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/running-scripts-before-or-after-a-job

    When using non-ephemeral, self-hosted runners the default cache directory can grow unbounded.
    In this case, it may not be optimal to share the cache between jobs. Instead, move the cache
    inside the GitHub Workspace and remove it once the job finishes using a
    [Post Job Hook][post-job-hook].

    ```yaml
    install_job:
      env:
        # Configure a relative location for the uv cache
        UV_CACHE_DIR: ${{ github.workspace }}/.cache/uv
    ```

    Using a post job hook requires setting the `ACTIONS_RUNNER_HOOK_JOB_STARTED` environment
    variable on the self-hosted runner to the path of a cleanup script such as the one shown below.

    ```sh title="clean-uv-cache.sh"
    #!/usr/bin/env sh
    uv cache clean
    ```

## Using `uv pip`

If using the `uv pip` interface instead of the uv project interface, uv requires a virtual
environment by default. To allow installing packages into the system environment, use the `--system`
flag on all `uv` invocations or set the `UV_SYSTEM_PYTHON` variable.

The `UV_SYSTEM_PYTHON` variable can be defined in at different scopes.

Opt-in for the entire workflow by defining it at the top level:

```yaml title="example.yml"
env:
  UV_SYSTEM_PYTHON: 1

jobs: ...
```

Or, opt-in for a specific job in the workflow:

```yaml title="example.yml"
jobs:
  install_job:
    env:
      UV_SYSTEM_PYTHON: 1
    ...
```

Or, opt-in for a specific step in a job:

```yaml title="example.yml"
steps:
  - name: Install requirements
    run: uv pip install -r requirements.txt
    env:
      UV_SYSTEM_PYTHON: 1
```

To opt-out again, the `--no-system` flag can be used in any uv invocation.

## Private repos

If your project has [dependencies](../../concepts/projects/dependencies.md#git) on private GitHub
repositories, you will need to configure a [personal access token (PAT)][PAT] to allow uv to fetch
them.

After creating a PAT that has read access to the private repositories, add it as a [repository
secret].

Then, you can use the [`gh`](https://cli.github.com/) CLI (which is installed in GitHub Actions
runners by default) to configure a
[credential helper for Git](../../concepts/authentication/git.md#git-credential-helpers) to use the
PAT for queries to repositories hosted on `github.com`.

For example, if you called your repository secret `MY_PAT`:

```yaml title="example.yml"
steps:
  - name: Register the personal access token
    run: echo "${{ secrets.MY_PAT }}" | gh auth login --with-token
  - name: Configure the Git credential helper
    run: gh auth setup-git
```

[PAT]:
  https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
[repository secret]:
  https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository

## Publishing to PyPI

uv can be used to build and publish your package to PyPI from GitHub Actions. We provide a
standalone example alongside this guide in
[astral-sh/trusted-publishing-examples](https://github.com/astral-sh/trusted-publishing-examples).
The workflow uses [trusted publishing](https://docs.pypi.org/trusted-publishers/), so no credentials
need to be configured.

In the example workflow, we use a script to test that the source distribution and the wheel are both
functional and we didn't miss any files. This step is recommended, but optional.

First, add a release workflow to your project:

```yaml title=".github/workflows/publish.yml"
name: "Publish"

on:
  push:
    tags:
      # Publish on any tag starting with a `v`, e.g., v0.1.0
      - v*

jobs:
  run:
    runs-on: ubuntu-latest
    environment:
      name: pypi
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@v5
      - name: Install uv
        uses: astral-sh/setup-uv@v6
      - name: Install Python 3.13
        run: uv python install 3.13
      - name: Build
        run: uv build
      # Check that basic features work and we didn't miss to include crucial files
      - name: Smoke test (wheel)
        run: uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py
      - name: Smoke test (source distribution)
        run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py
      - name: Publish
        run: uv publish
```

Then, create the environment defined in the workflow in the GitHub repository under "Settings" ->
"Environments".

![GitHub settings dialog showing how to add the "pypi" environment under "Settings" -> "Environments"](../../assets/github-add-environment.png)

Add a [trusted publisher](https://docs.pypi.org/trusted-publishers/adding-a-publisher/) to your PyPI
project in the project settings under "Publishing". Ensure that all fields match with your GitHub
configuration.

![PyPI project publishing settings dialog showing how to set all fields for a trusted publisher configuration](../../assets/pypi-add-trusted-publisher.png)

After saving:

![PyPI project publishing settings dialog showing the configured trusted publishing settings](../../assets/pypi-with-trusted-publisher.png)

Finally, tag a release and push it. Make sure it starts with `v` to match the pattern in the
workflow.

```console
$ git tag -a v0.1.0 -m v0.1.0
$ git push --tags
```

    ---
title: Using uv in GitLab CI/CD
description: A guide to using uv in GitLab CI/CD, including installation, setting up Python,
  installing dependencies, and more.
---

# Using uv in GitLab CI/CD

## Using the uv image

Astral provides [Docker images](docker.md#available-images) with uv preinstalled.
Select a variant that is suitable for your workflow.

```yaml title="gitlab-ci.yml"
variables:
  UV_VERSION: "0.5"
  PYTHON_VERSION: "3.12"
  BASE_LAYER: bookworm-slim
  # GitLab CI creates a separate mountpoint for the build directory,
  # so we need to copy instead of using hard links.
  UV_LINK_MODE: copy

uv:
  image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
  script:
    # your `uv` commands
```

!!! note

    If you are using a distroless image, you have to specify the entrypoint:
    ```yaml
    uv:
      image:
        name: ghcr.io/astral-sh/uv:$UV_VERSION
        entrypoint: [""]
      # ...
    ```

## Caching

Persisting the uv cache between workflow runs can improve performance.

```yaml
uv-install:
  variables:
    UV_CACHE_DIR: .uv-cache
  cache:
    - key:
        files:
          - uv.lock
      paths:
        - $UV_CACHE_DIR
  script:
    # Your `uv` commands
    - uv cache prune --ci
```

See the [GitLab caching documentation](https://docs.gitlab.com/ee/ci/caching/) for more details on
configuring caching.

Using `uv cache prune --ci` at the end of the job is recommended to reduce cache size. See the [uv
cache documentation](../../concepts/cache.md#caching-in-continuous-integration) for more details.

## Using `uv pip`

If using the `uv pip` interface instead of the uv project interface, uv requires a virtual
environment by default. To allow installing packages into the system environment, use the `--system`
flag on all uv invocations or set the `UV_SYSTEM_PYTHON` variable.

The `UV_SYSTEM_PYTHON` variable can be defined in at different scopes. You can read more about
how [variables and their precedence works in GitLab here](https://docs.gitlab.com/ee/ci/variables/)

Opt-in for the entire workflow by defining it at the top level:

```yaml title="gitlab-ci.yml"
variables:
  UV_SYSTEM_PYTHON: 1

# [...]
```

To opt-out again, the `--no-system` flag can be used in any uv invocation.

When persisting the cache, you may want to use `requirements.txt` or `pyproject.toml` as
your cache key files instead of `uv.lock`.

    # Integration guides

Learn how to integrate uv with other software:

- [Using in Docker images](./docker.md)
- [Using with Jupyter notebooks](./jupyter.md)
- [Using with marimo notebooks](./marimo.md)
- [Using with pre-commit](./pre-commit.md)
- [Using in GitHub Actions](./github.md)
- [Using in GitLab CI/CD](./gitlab.md)
- [Using with alternative package indexes](./alternative-indexes.md)
- [Installing PyTorch](./pytorch.md)
- [Building a FastAPI application](./fastapi.md)
- [Using with AWS Lambda](./aws-lambda.md)
- [Using with Coiled](./coiled.md)

Or, explore the [concept documentation](../../concepts/index.md) for comprehensive breakdown of each
feature.

    ---
title: Using uv with Jupyter
description:
  A complete guide to using uv with Jupyter notebooks for interactive computing, data analysis, and
  visualization, including kernel management and virtual environment integration.
---

# Using uv with Jupyter

The [Jupyter](https://jupyter.org/) notebook is a popular tool for interactive computing, data
analysis, and visualization. You can use Jupyter with uv in a few different ways, either to interact
with a project, or as a standalone tool.

## Using Jupyter within a project

If you're working within a [project](../../concepts/projects/index.md), you can start a Jupyter
server with access to the project's virtual environment via the following:

```console
$ uv run --with jupyter jupyter lab
```

By default, `jupyter lab` will start the server at
[http://localhost:8888/lab](http://localhost:8888/lab).

Within a notebook, you can import your project's modules as you would in any other file in the
project. For example, if your project depends on `requests`, `import requests` will import
`requests` from the project's virtual environment.

If you're looking for read-only access to the project's virtual environment, then there's nothing
more to it. However, if you need to install additional packages from within the notebook, there are
a few extra details to consider.

### Creating a kernel

If you need to install packages from within the notebook, we recommend creating a dedicated kernel
for your project. Kernels enable the Jupyter server to run in one environment, with individual
notebooks running in their own, separate environments.

In the context of uv, we can create a kernel for a project while installing Jupyter itself in an
isolated environment, as in `uv run --with jupyter jupyter lab`. Creating a kernel for the project
ensures that the notebook is hooked up to the correct environment, and that any packages installed
from within the notebook are installed into the project's virtual environment.

To create a kernel, you'll need to install `ipykernel` as a development dependency:

```console
$ uv add --dev ipykernel
```

Then, you can create the kernel for `project` with:

```console
$ uv run ipython kernel install --user --env VIRTUAL_ENV $(pwd)/.venv --name=project
```

From there, start the server with:

```console
$ uv run --with jupyter jupyter lab
```

When creating a notebook, select the `project` kernel from the dropdown. Then use `!uv add pydantic`
to add `pydantic` to the project's dependencies, or `!uv pip install pydantic` to install `pydantic`
into the project's virtual environment without persisting the change to the project `pyproject.toml`
or `uv.lock` files. Either command will make `import pydantic` work within the notebook.

### Installing packages without a kernel

If you don't want to create a kernel, you can still install packages from within the notebook.
However, there are a few caveats to consider.

Though `uv run --with jupyter` runs in an isolated environment, within the notebook itself,
`!uv add` and related commands will modify the _project's_ environment, even without a kernel.

For example, running `!uv add pydantic` from within a notebook will add `pydantic` to the project's
dependencies and virtual environment, such that `import pydantic` will work immediately, without
further configuration or a server restart.

However, since the Jupyter server is the "active" environment, `!uv pip install` will install
package's into _Jupyter's_ environment, not the project environment. Such dependencies will persist
for the lifetime of the Jupyter server, but may disappear on subsequent `jupyter` invocations.

If you're working with a notebook that relies on pip (e.g., via the `%pip` magic), you can include
pip in your project's virtual environment by running `uv venv --seed` prior to starting the Jupyter
server. For example, given:

```console
$ uv venv --seed
$ uv run --with jupyter jupyter lab
```

Subsequent `%pip install` invocations within the notebook will install packages into the project's
virtual environment. However, such modifications will _not_ be reflected in the project's
`pyproject.toml` or `uv.lock` files.

## Using Jupyter as a standalone tool

If you ever need ad hoc access to a notebook (i.e., to run a Python snippet interactively), you can
start a Jupyter server at any time with `uv tool run jupyter lab`. This will run a Jupyter server in
an isolated environment.

## Using Jupyter with a non-project environment

If you need to run Jupyter in a virtual environment that isn't associated with a
[project](../../concepts/projects/index.md) (e.g., has no `pyproject.toml` or `uv.lock`), you can do
so by adding Jupyter to the environment directly. For example:

=== "macOS and Linux"

    ```console
    $ uv venv --seed
    $ uv pip install pydantic
    $ uv pip install jupyterlab
    $ .venv/bin/jupyter lab
    ```

=== "Windows"

    ```pwsh-session
    PS> uv venv --seed
    PS> uv pip install pydantic
    PS> uv pip install jupyterlab
    PS> .venv\Scripts\jupyter lab
    ```

From here, `import pydantic` will work within the notebook, and you can install additional packages
via `!uv pip install`, or even `!pip install`.

## Using Jupyter from VS Code

You can also engage with Jupyter notebooks from within an editor like VS Code. To connect a
uv-managed project to a Jupyter notebook within VS Code, we recommend creating a kernel for the
project, as in the following:

```console
# Create a project.
$ uv init project

# Move into the project directory.
$ cd project

# Add ipykernel as a dev dependency.
$ uv add --dev ipykernel

# Open the project in VS Code.
$ code .
```

Once the project directory is open in VS Code, you can create a new Jupyter notebook by selecting
"Create: New Jupyter Notebook" from the command palette. When prompted to select a kernel, choose
"Python Environments" and select the virtual environment you created earlier (e.g.,
`.venv/bin/python` on macOS and Linux, or `.venv\Scripts\python` on Windows).

!!! note

    VS Code requires `ipykernel` to be present in the project environment. If you'd prefer to avoid
    adding `ipykernel` as a dev dependency, you can install it directly into the project environment
    with `uv pip install ipykernel`.

If you need to manipulate the project's environment from within the notebook, you may need to add
`uv` as an explicit development dependency:

```console
$ uv add --dev uv
```

From there, you can use `!uv add pydantic` to add `pydantic` to the project's dependencies, or
`!uv pip install pydantic` to install `pydantic` into the project's virtual environment without
updating the project's `pyproject.toml` or `uv.lock` files.

    ---
title: Using uv with marimo
description:
  A complete guide to using uv with marimo notebooks for interactive computing, script execution,
  and data apps.
---

# Using uv with marimo

[marimo](https://github.com/marimo-team/marimo) is an open-source Python notebook that blends
interactive computing with the reproducibility and reusability of traditional software, letting you
version with Git, run as scripts, and share as apps. Because marimo notebooks are stored as pure
Python scripts, they are able to integrate tightly with uv.

You can readily use marimo as a standalone tool, as self-contained scripts, in projects, and in
non-project environments.

## Using marimo as a standalone tool

For ad-hoc access to marimo notebooks, start a marimo server at any time in an isolated environment
with:

```console
$ uvx marimo edit
```

Start a specific notebook with:

```console
$ uvx marimo edit my_notebook.py
```

## Using marimo with inline script metadata

Because marimo notebooks are stored as Python scripts, they can encapsulate their own dependencies
using inline script metadata, via uv's [support for scripts](../../guides/scripts.md). For example,
to add `numpy` as a dependency to your notebook, use this command:

```console
$ uv add --script my_notebook.py numpy
```

To interactively edit a notebook containing inline script metadata, use:

```console
$ uvx marimo edit --sandbox my_notebook.py
```

marimo will automatically use uv to start your notebook in an isolated virtual environment with your
script's dependencies. Packages installed from the marimo UI will automatically be added to the
notebook's script metadata.

You can optionally run these notebooks as Python scripts, without opening an interactive session:

```console
$ uv run my_notebook.py
```

## Using marimo within a project

If you're working within a [project](../../concepts/projects/index.md), you can start a marimo
notebook with access to the project's virtual environment via the following command (assuming marimo
is a project dependency):

```console
$ uv run marimo edit my_notebook.py
```

To make additional packages available to your notebook, either add them to your project with
`uv add`, or use marimo's built-in package installation UI, which will invoke `uv add` on your
behalf.

If marimo is not a project dependency, you can still run a notebook with the following command:

```console
$ uv run --with marimo marimo edit my_notebook.py
```

This will let you import your project's modules while editing your notebook. However, packages
installed via marimo's UI when running in this way will not be added to your project, and may
disappear on subsequent marimo invocations.

## Using marimo in a non-project environment

To run marimo in a virtual environment that isn't associated with a
[project](../../concepts/projects/index.md), add marimo to the environment directly:

```console
$ uv venv
$ uv pip install numpy
$ uv pip install marimo
$ uv run marimo edit
```

From here, `import numpy` will work within the notebook, and marimo's UI installer will add packages
to the environment with `uv pip install` on your behalf.

## Running marimo notebooks as scripts

Regardless of how your dependencies are managed (with inline script metadata, within a project, or
with a non-project environment), you can run marimo notebooks as scripts with:

```console
$ uv run my_notebook.py
```

This executes your notebook as a Python script, without opening an interactive session in your
browser.

    ---
title: Using uv with pre-commit
description:
  A guide to using uv with pre-commit to automatically update lock files, export requirements, and
  compile requirements files.
---

# Using uv in pre-commit

An official pre-commit hook is provided at
[`astral-sh/uv-pre-commit`](https://github.com/astral-sh/uv-pre-commit).

To use uv with pre-commit, add one of the following examples to the `repos` list in the
`.pre-commit-config.yaml`.

To make sure your `uv.lock` file is up to date even if your `pyproject.toml` file was changed:

```yaml title=".pre-commit-config.yaml"
repos:
  - repo: https://github.com/astral-sh/uv-pre-commit
    # uv version.
    rev: 0.8.22
    hooks:
      - id: uv-lock
```

To keep a `requirements.txt` file in sync with your `uv.lock` file:

```yaml title=".pre-commit-config.yaml"
repos:
  - repo: https://github.com/astral-sh/uv-pre-commit
    # uv version.
    rev: 0.8.22
    hooks:
      - id: uv-export
```

To compile requirements files:

```yaml title=".pre-commit-config.yaml"
repos:
  - repo: https://github.com/astral-sh/uv-pre-commit
    # uv version.
    rev: 0.8.22
    hooks:
      # Compile requirements
      - id: pip-compile
        args: [requirements.in, -o, requirements.txt]
```

To compile alternative requirements files, modify `args` and `files`:

```yaml title=".pre-commit-config.yaml"
repos:
  - repo: https://github.com/astral-sh/uv-pre-commit
    # uv version.
    rev: 0.8.22
    hooks:
      # Compile requirements
      - id: pip-compile
        args: [requirements-dev.in, -o, requirements-dev.txt]
        files: ^requirements-dev\.(in|txt)$
```

To run the hook over multiple files at the same time, add additional entries:

```yaml title=".pre-commit-config.yaml"
repos:
  - repo: https://github.com/astral-sh/uv-pre-commit
    # uv version.
    rev: 0.8.22
    hooks:
      # Compile requirements
      - id: pip-compile
        name: pip-compile requirements.in
        args: [requirements.in, -o, requirements.txt]
      - id: pip-compile
        name: pip-compile requirements-dev.in
        args: [requirements-dev.in, -o, requirements-dev.txt]
        files: ^requirements-dev\.(in|txt)$
```

    ---
title: Using uv with PyTorch
description:
  A guide to using uv with PyTorch, including installing PyTorch, configuring per-platform and
  per-accelerator builds, and more.
---

# Using uv with PyTorch

The [PyTorch](https://pytorch.org/) ecosystem is a popular choice for deep learning research and
development. You can use uv to manage PyTorch projects and PyTorch dependencies across different
Python versions and environments, even controlling for the choice of accelerator (e.g., CPU-only vs.
CUDA).

!!! note

    Some of the features outlined in this guide require uv version 0.5.3 or later. We recommend upgrading prior to configuring PyTorch.

## Installing PyTorch

From a packaging perspective, PyTorch has a few uncommon characteristics:

- Many PyTorch wheels are hosted on a dedicated index, rather than the Python Package Index (PyPI).
  As such, installing PyTorch often requires configuring a project to use the PyTorch index.
- PyTorch produces distinct builds for each accelerator (e.g., CPU-only, CUDA). Since there's no
  standardized mechanism for specifying these accelerators when publishing or installing, PyTorch
  encodes them in the local version specifier. As such, PyTorch versions will often look like
  `2.5.1+cpu`, `2.5.1+cu121`, etc.
- Builds for different accelerators are published to different indexes. For example, the `+cpu`
  builds are published on https://download.pytorch.org/whl/cpu, while the `+cu121` builds are
  published on https://download.pytorch.org/whl/cu121.

As such, the necessary packaging configuration will vary depending on both the platforms you need to
support and the accelerators you want to enable.

To start, consider the following (default) configuration, which would be generated by running
`uv init --python 3.12` followed by `uv add torch torchvision`.

In this case, PyTorch would be installed from PyPI, which hosts CPU-only wheels for Windows and
macOS, and GPU-accelerated wheels on Linux (targeting CUDA 12.6):

```toml
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
  "torch>=2.7.0",
  "torchvision>=0.22.0",
]
```

!!! tip "Supported Python versions"

    At time of writing, PyTorch does not yet publish wheels for Python 3.14; as such projects with
    `requires-python = ">=3.14"` may fail to resolve. See the
    [compatibility matrix](https://github.com/pytorch/pytorch/blob/main/RELEASE.md#release-compatibility-matrix).

This is a valid configuration for projects that want to use CPU builds on Windows and macOS, and
CUDA-enabled builds on Linux. However, if you need to support different platforms or accelerators,
you'll need to configure the project accordingly.

## Using a PyTorch index

In some cases, you may want to use a specific PyTorch variant across all platforms. For example, you
may want to use the CPU-only builds on Linux too.

In such cases, the first step is to add the relevant PyTorch index to your `pyproject.toml`:

=== "CPU-only"

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

=== "CUDA 11.8"

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

=== "CUDA 12.6"

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

=== "CUDA 12.8"

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

=== "ROCm6"

    ```toml
    [[tool.uv.index]]
    name = "pytorch-rocm"
    url = "https://download.pytorch.org/whl/rocm6.3"
    explicit = true
    ```

=== "Intel GPUs"

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

We recommend the use of `explicit = true` to ensure that the index is _only_ used for `torch`,
`torchvision`, and other PyTorch-related packages, as opposed to generic dependencies like `jinja2`,
which should continue to be sourced from the default index (PyPI).

Next, update the `pyproject.toml` to point `torch` and `torchvision` to the desired index:

=== "CPU-only"

    ```toml
    [tool.uv.sources]
    torch = [
      { index = "pytorch-cpu" },
    ]
    torchvision = [
      { index = "pytorch-cpu" },
    ]
    ```

=== "CUDA 11.8"

    PyTorch doesn't publish CUDA builds for macOS. As such, we gate on `sys_platform` to instruct uv to use
    the PyTorch index on Linux and Windows, but fall back to PyPI on macOS:

    ```toml
    [tool.uv.sources]
    torch = [
      { index = "pytorch-cu118", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
    ]
    torchvision = [
      { index = "pytorch-cu118", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
    ]
    ```

=== "CUDA 12.6"

    PyTorch doesn't publish CUDA builds for macOS. As such, we gate on `sys_platform` to instruct uv to limit
    the PyTorch index to Linux and Windows, falling back to PyPI on macOS:

    ```toml
    [tool.uv.sources]
    torch = [
      { index = "pytorch-cu126", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
    ]
    torchvision = [
      { index = "pytorch-cu126", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
    ]
    ```

=== "CUDA 12.8"

    PyTorch doesn't publish CUDA builds for macOS. As such, we gate on `sys_platform` to instruct uv to limit
    the PyTorch index to Linux and Windows, falling back to PyPI on macOS:

    ```toml
    [tool.uv.sources]
    torch = [
      { index = "pytorch-cu128", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
    ]
    torchvision = [
      { index = "pytorch-cu128", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
    ]
    ```

=== "ROCm6"

    PyTorch doesn't publish ROCm6 builds for macOS or Windows. As such, we gate on `sys_platform` to instruct uv
    to limit the PyTorch index to Linux, falling back to PyPI on macOS and Windows:

    ```toml
    [tool.uv.sources]
    torch = [
      { index = "pytorch-rocm", marker = "sys_platform == 'linux'" },
    ]
    torchvision = [
      { index = "pytorch-rocm", marker = "sys_platform == 'linux'" },
    ]
    # ROCm6 support relies on `pytorch-triton-rocm`, which should also be installed from the PyTorch index
    # (and included in `project.dependencies`).
    pytorch-triton-rocm = [
      { index = "pytorch-rocm", marker = "sys_platform == 'linux'" },
    ]
    ```

=== "Intel GPUs"

    PyTorch doesn't publish Intel GPU builds for macOS. As such, we gate on `sys_platform` to instruct uv to limit
    the PyTorch index to Linux and Windows, falling back to PyPI on macOS:

    ```toml
    [tool.uv.sources]
    torch = [
      { index = "pytorch-xpu", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
    ]
    torchvision = [
      { index = "pytorch-xpu", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
    ]
    # Intel GPU support relies on `pytorch-triton-xpu`, which should also be installed from the PyTorch index
    # (and included in `project.dependencies`).
    pytorch-triton-xpu = [
      { index = "pytorch-xpu", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
    ]
    ```

As a complete example, the following project would use PyTorch's CPU-only builds on all platforms:

```toml
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12.0"
dependencies = [
  "torch>=2.7.0",
  "torchvision>=0.22.0",
]

[tool.uv.sources]
torch = [
    { index = "pytorch-cpu" },
]
torchvision = [
    { index = "pytorch-cpu" },
]

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

## Configuring accelerators with environment markers

In some cases, you may want to use CPU-only builds in one environment (e.g., macOS and Windows), and
CUDA-enabled builds in another (e.g., Linux).

With `tool.uv.sources`, you can use environment markers to specify the desired index for each
platform. For example, the following configuration would use PyTorch's CUDA-enabled builds on Linux,
and CPU-only builds on all other platforms (e.g., macOS and Windows):

```toml
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12.0"
dependencies = [
  "torch>=2.7.0",
  "torchvision>=0.22.0",
]

[tool.uv.sources]
torch = [
  { index = "pytorch-cpu", marker = "sys_platform != 'linux'" },
  { index = "pytorch-cu128", marker = "sys_platform == 'linux'" },
]
torchvision = [
  { index = "pytorch-cpu", marker = "sys_platform != 'linux'" },
  { index = "pytorch-cu128", marker = "sys_platform == 'linux'" },
]

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

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

Similarly, the following configuration would use PyTorch's AMD GPU builds on Linux, and CPU-only
builds on Windows and macOS (by way of falling back to PyPI):

```toml
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12.0"
dependencies = [
  "torch>=2.7.0",
  "torchvision>=0.22.0",
  "pytorch-triton-rocm>=3.3.0 ; sys_platform == 'linux'",
]

[tool.uv.sources]
torch = [
  { index = "pytorch-rocm", marker = "sys_platform == 'linux'" },
]
torchvision = [
  { index = "pytorch-rocm", marker = "sys_platform == 'linux'" },
]
pytorch-triton-rocm = [
  { index = "pytorch-rocm", marker = "sys_platform == 'linux'" },
]

[[tool.uv.index]]
name = "pytorch-rocm"
url = "https://download.pytorch.org/whl/rocm6.3"
explicit = true
```

Or, for Intel GPU builds:

```toml
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12.0"
dependencies = [
  "torch>=2.7.0",
  "torchvision>=0.22.0",
  "pytorch-triton-xpu>=3.3.0 ; sys_platform == 'win32' or sys_platform == 'linux'",
]

[tool.uv.sources]
torch = [
  { index = "pytorch-xpu", marker = "sys_platform == 'win32' or sys_platform == 'linux'" },
]
torchvision = [
  { index = "pytorch-xpu", marker = "sys_platform == 'win32' or sys_platform == 'linux'" },
]
pytorch-triton-xpu = [
  { index = "pytorch-xpu", marker = "sys_platform == 'win32' or sys_platform == 'linux'" },
]

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

## Configuring accelerators with optional dependencies

In some cases, you may want to use CPU-only builds in some cases, but CUDA-enabled builds in others,
with the choice toggled by a user-provided extra (e.g., `uv sync --extra cpu` vs.
`uv sync --extra cu128`).

With `tool.uv.sources`, you can use extra markers to specify the desired index for each enabled
extra. For example, the following configuration would use PyTorch's CPU-only for
`uv sync --extra cpu` and CUDA-enabled builds for `uv sync --extra cu128`:

```toml
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12.0"
dependencies = []

[project.optional-dependencies]
cpu = [
  "torch>=2.7.0",
  "torchvision>=0.22.0",
]
cu128 = [
  "torch>=2.7.0",
  "torchvision>=0.22.0",
]

[tool.uv]
conflicts = [
  [
    { extra = "cpu" },
    { extra = "cu128" },
  ],
]

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

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

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

!!! note

    Since GPU-accelerated builds aren't available on macOS, the above configuration will fail to install
    on macOS when the `cu128` extra is enabled.

## The `uv pip` interface

While the above examples are focused on uv's project interface (`uv lock`, `uv sync`, `uv run`,
etc.), PyTorch can also be installed via the `uv pip` interface.

PyTorch itself offers a [dedicated interface](https://pytorch.org/get-started/locally/) to determine
the appropriate pip command to run for a given target configuration. For example, you can install
stable, CPU-only PyTorch on Linux with:

```shell
$ pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
```

To use the same workflow with uv, replace `pip3` with `uv pip`:

```shell
$ uv pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
```

## Automatic backend selection

uv supports automatic selection of the appropriate PyTorch index via the `--torch-backend=auto`
command-line argument (or the `UV_TORCH_BACKEND=auto` environment variable), as in:

```shell
$ # With a command-line argument.
$ uv pip install torch --torch-backend=auto

$ # With an environment variable.
$ UV_TORCH_BACKEND=auto uv pip install torch
```

When enabled, uv will query for the installed CUDA driver, AMD GPU versions, and Intel GPU presence,
then use the most-compatible PyTorch index for all relevant packages (e.g., `torch`, `torchvision`,
etc.). If no such GPU is found, uv will fall back to the CPU-only index. uv will continue to respect
existing index configuration for any packages outside the PyTorch ecosystem.

You can also select a specific backend (e.g., CUDA 12.6) with `--torch-backend=cu126` (or
`UV_TORCH_BACKEND=cu126`):

```shell
$ # With a command-line argument.
$ uv pip install torch torchvision --torch-backend=cu126

$ # With an environment variable.
$ UV_TORCH_BACKEND=cu126 uv pip install torch torchvision
```

On Windows, Intel GPU (XPU) is not automatically selected with `--torch-backend=auto`, but you can
manually specify it using `--torch-backend=xpu`:

```shell
$ # Manual selection for Intel GPU.
$ uv pip install torch torchvision --torch-backend=xpu
```

At present, `--torch-backend` is only available in the `uv pip` interface.

    # Migration guides

Learn how to migrate from other tools to uv:

- [Migrate from pip to uv projects](./pip-to-project.md)

!!! note

    Other guides, such as migrating from another project management tool, or from pip to `uv pip`
    are not yet available. See [#5200](https://github.com/astral-sh/uv/issues/5200) to track
    progress.

Or, explore the [integration guides](../integration/index.md) to learn how to use uv with other
software.

    # Migrating from pip to a uv project

This guide will discuss converting from a `pip` and `pip-tools` workflow centered on `requirements`
files to uv's project workflow using a `pyproject.toml` and `uv.lock` file.

!!! note

    If you're looking to migrate from `pip` and `pip-tools` to uv's drop-in interface or from an
    existing workflow where you're already using a `pyproject.toml`, those guides are not yet
    written. See [#5200](https://github.com/astral-sh/uv/issues/5200) to track progress.

We'll start with an overview of developing with `pip`, then discuss migrating to uv.

!!! tip

    If you're familiar with the ecosystem, you can jump ahead to the
    [requirements file import](#importing-requirements-files) instructions.

## Understanding pip workflows

### Project dependencies

When you want to use a package in your project, you need to install it first. `pip` supports
imperative installation of packages, e.g.:

```console
$ pip install fastapi
```

This installs the package into the environment that `pip` is installed in. This may be a virtual
environment, or, the global environment of your system's Python installation.

Then, you can run a Python script that requires the package:

```python title="example.py"
import fastapi
```

It's best practice to create a virtual environment for each project, to avoid mixing packages
between them. For example:

```console
$ python -m venv
$ source .venv/bin/activate
$ pip ...
```

We will revisit this topic in the [project environments section](#project-environments) below.

### Requirements files

When sharing projects with others, it's useful to declare all the packages you require upfront.
`pip` supports installing requirements from a file, e.g.:

```python title="requirements.txt"
fastapi
```

```console
$ pip install -r requirements.txt
```

Notice above that `fastapi` is not "locked" to a specific version — each person working on the
project may have a different version of `fastapi` installed. `pip-tools` was created to improve this
experience.

When using `pip-tools`, requirements files specify both the dependencies for your project and lock
dependencies to a specific version — the file extension is used to differentiate between the two.
For example, if you require `fastapi` and `pydantic`, you'd specify these in a `requirements.in`
file:

```python title="requirements.in"
fastapi
pydantic>2
```

Notice there's a version constraint on `pydantic` — this means only `pydantic` versions later than
`2.0.0` can be used. In contrast, `fastapi` does not have a version constraint — any version can be
used.

These dependencies can be compiled into a `requirements.txt` file:

```console
$ pip-compile requirements.in -o requirements.txt
```

```python title="requirements.txt"
annotated-types==0.7.0
    # via pydantic
anyio==4.8.0
    # via starlette
fastapi==0.115.11
    # via -r requirements.in
idna==3.10
    # via anyio
pydantic==2.10.6
    # via
    #   -r requirements.in
    #   fastapi
pydantic-core==2.27.2
    # via pydantic
sniffio==1.3.1
    # via anyio
starlette==0.46.1
    # via fastapi
typing-extensions==4.12.2
    # via
    #   fastapi
    #   pydantic
    #   pydantic-core
```

Here, all the versions constraints are _exact_. Only a single version of each package can be used.
The above example was generated with `uv pip compile`, but could also be generated with
`pip-compile` from `pip-tools`.

Though less common, the `requirements.txt` can also be generated using `pip freeze`, by first
installing the input dependencies into the environment then exporting the installed versions:

```console
$ pip install -r requirements.in
$ pip freeze > requirements.txt
```

```python title="requirements.txt"
annotated-types==0.7.0
anyio==4.8.0
fastapi==0.115.11
idna==3.10
pydantic==2.10.6
pydantic-core==2.27.2
sniffio==1.3.1
starlette==0.46.1
typing-extensions==4.12.2
```

After compiling dependencies into a locked set of versions, these files are committed to version
control and distributed with the project.

Then, when someone wants to use the project, they install from the requirements file:

```console
$ pip install -r requirements.txt
```

<!--- TODO: Discuss equivalent commands for `uv pip compile` and `pip compile` -->

### Development dependencies

The requirements file format can only describe a single set of dependencies at once. This means if
you have additional _groups_ of dependencies, such as development dependencies, they need separate
files. For example, we'll create a `-dev` dependency file:

```python title="requirements-dev.in"
-r requirements.in
-c requirements.txt

pytest
```

Notice the base requirements are included with `-r requirements.in`. This ensures your development
environment considers _all_ of the dependencies together. The `-c requirements.txt` _constrains_ the
package version to ensure that the `requirements-dev.txt` uses the same versions as
`requirements.txt`.

!!! note

    It's common to use `-r requirements.txt` directly instead of using both
    `-r requirements.in`, and `-c requirements.txt`. There's no difference in the resulting package
    versions, but using both files produces annotations which allow you to determine which
    dependencies are _direct_ (annotated with `-r requirements.in`) and which are _indirect_ (only
    annotated with `-c requirements.txt`).

The compiled development dependencies look like:

```python title="requirements-dev.txt"
annotated-types==0.7.0
    # via
    #   -c requirements.txt
    #   pydantic
anyio==4.8.0
    # via
    #   -c requirements.txt
    #   starlette
fastapi==0.115.11
    # via
    #   -c requirements.txt
    #   -r requirements.in
idna==3.10
    # via
    #   -c requirements.txt
    #   anyio
iniconfig==2.0.0
    # via pytest
packaging==24.2
    # via pytest
pluggy==1.5.0
    # via pytest
pydantic==2.10.6
    # via
    #   -c requirements.txt
    #   -r requirements.in
    #   fastapi
pydantic-core==2.27.2
    # via
    #   -c requirements.txt
    #   pydantic
pytest==8.3.5
    # via -r requirements-dev.in
sniffio==1.3.1
    # via
    #   -c requirements.txt
    #   anyio
starlette==0.46.1
    # via
    #   -c requirements.txt
    #   fastapi
typing-extensions==4.12.2
    # via
    #   -c requirements.txt
    #   fastapi
    #   pydantic
    #   pydantic-core
```

As with the base dependency files, these are committed to version control and distributed with the
project. When someone wants to work on the project, they'll install from the requirements file:

```console
$ pip install -r requirements-dev.txt
```

### Platform-specific dependencies

When compiling dependencies with `pip` or `pip-tools`, the result is only usable on the same
platform as it is generated on. This poses a problem for projects which need to be usable on
multiple platforms, such as Windows and macOS.

For example, take a simple dependency:

```python title="requirements.in"
tqdm
```

On Linux, this compiles to:

```python title="requirements-linux.txt"
tqdm==4.67.1
    # via -r requirements.in
```

While on Windows, this compiles to:

```python title="requirements-win.txt"
colorama==0.4.6
    # via tqdm
tqdm==4.67.1
    # via -r requirements.in
```

`colorama` is a Windows-only dependency of `tqdm`.

When using `pip` and `pip-tools`, a project needs to declare a requirements lock file for each
supported platform.

!!! note

    uv's resolver can compile dependencies for multiple platforms at once (see ["universal resolution"](../../concepts/resolution.md#universal-resolution)),
    allowing you to use a single `requirements.txt` for all platforms:

    ```console
    $ uv pip compile --universal requirements.in
    ```

    ```python title="requirements.txt"
    colorama==0.4.6 ; sys_platform == 'win32'
        # via tqdm
    tqdm==4.67.1
        # via -r requirements.in
    ```

    This resolution mode is also used when using a `pyproject.toml` and `uv.lock`.

## Migrating to a uv project

### The `pyproject.toml`

The `pyproject.toml` is a standardized file for Python project metadata. It replaces
`requirements.in` files, allowing you to represent arbitrary groups of project dependencies. It also
provides a centralized location for metadata about your project, such as the build system or tool
settings.

<!-- TODO: Link to the official docs on this or write more -->

For example, the `requirements.in` and `requirements-dev.in` files above can be translated to a
`pyproject.toml` as follows:

```toml title="pyproject.toml"
[project]
name = "example"
version = "0.0.1"
dependencies = [
    "fastapi",
    "pydantic>2"
]

[dependency-groups]
dev = ["pytest"]
```

We'll discuss the commands necessary to automate these imports below.

### The uv lockfile

uv uses a lockfile (`uv.lock`) file to lock package versions. The format of this file is specific to
uv, allowing uv to support advanced features. It replaces `requirements.txt` files.

The lockfile will be automatically created and populated when adding dependencies, but you can
explicitly create it with `uv lock`.

Unlike `requirements.txt` files, the `uv.lock` file can represent arbitrary groups of dependencies,
so multiple files are not needed to lock development dependencies.

The uv lockfile is always [universal](../../concepts/resolution.md#universal-resolution), so
multiple files are not needed to
[lock dependencies for each platform](#platform-specific-dependencies). This ensures that all
developers are using consistent, locked versions of dependencies regardless of their machine.

The uv lockfile also supports concepts like
[pinning packages to specific indexes](../../concepts/indexes.md#pinning-a-package-to-an-index),
which is not representable in `requirements.txt` files.

!!! tip

    If you only need to lock for a subset of platforms, use the
    [`tool.uv.environments`](../../concepts/resolution.md#limited-resolution-environments) setting
    to limit the resolution and lockfile.

To learn more, see the [lockfile](../../concepts/projects/layout.md#the-lockfile) documentation.

### Importing requirements files

First, create a `pyproject.toml` if you have not already:

```console
$ uv init
```

Then, the easiest way to import requirements is with `uv add`:

```console
$ uv add -r requirements.in
```

However, there is some nuance to this transition. Notice we used the `requirements.in` file, which
does not pin to exact versions of packages so uv will solve for new versions of these packages. You
may want to continue using your previously locked versions from your `requirements.txt` so, when
switching over to uv, none of your dependency versions change.

The solution is to add your locked versions as _constraints_. uv supports using these on `add` to
preserve locked versions:

```console
$ uv add -r requirements.in -c requirements.txt
```

Your existing versions will be retained when producing a `uv.lock` file.

#### Importing platform-specific constraints

If your platform-specific dependencies have been compiled into separate files, you can still
transition to a universal lockfile. However, you cannot just use `-c` to specify constraints from
your existing platform-specific `requirements.txt` files because they do not include markers
describing the environment and will consequently conflict.

To add the necessary markers, use `uv pip compile` to convert your existing files. For example,
given the following:

```python title="requirements-win.txt"
colorama==0.4.6
    # via tqdm
tqdm==4.67.1
    # via -r requirements.in
```

The markers can be added with:

```console
$ uv pip compile requirements.in -o requirements-win.txt --python-platform windows --no-strip-markers
```

Notice the resulting output includes a Windows marker on `colorama`:

```python title="requirements-win.txt"
colorama==0.4.6 ; sys_platform == 'win32'
    # via tqdm
tqdm==4.67.1
    # via -r requirements.in
```

When using `-o`, uv will constrain the versions to match the existing output file, if it can.

Markers can be added for other platforms by changing the `--python-platform` and `-o` values for
each requirements file you need to import, e.g., to `linux` and `macos`.

Once each `requirements.txt` file has been transformed, the dependencies can be imported to the
`pyproject.toml` and `uv.lock` with `uv add`:

```console
$ uv add -r requirements.in -c requirements-win.txt -c requirements-linux.txt
```

#### Importing development dependency files

As discussed in the [development dependencies](#development-dependencies) section, it's common to
have groups of dependencies for development purposes.

To import development dependencies, use the `--dev` flag during `uv add`:

```console
$ uv add --dev -r requirements-dev.in -c requirements-dev.txt
```

If the `requirements-dev.in` includes the parent `requirements.in` via `-r`, it will need to be
stripped to avoid adding the base requirements to the `dev` dependency group. The following example
uses `sed` to strip lines that start with `-r`, then pipes the result to `uv add`:

```console
$ sed '/^-r /d' requirements-dev.in | uv add --dev -r - -c requirements-dev.txt
```

In addition to the `dev` dependency group, uv supports arbitrary group names. For example, if you
also have a dedicated set of dependencies for building your documentation, those can be imported to
a `docs` group:

```console
$ uv add -r requirements-docs.in -c requirements-docs.txt --group docs
```

### Project environments

Unlike `pip`, uv is not centered around the concept of an "active" virtual environment. Instead, uv
uses a dedicated virtual environment for each project in a `.venv` directory. This environment is
automatically managed, so when you run a command, like `uv add`, the environment is synced with the
project dependencies.

The preferred way to execute commands in the environment is with `uv run`, e.g.:

```console
$ uv run pytest
```

Prior to every `uv run` invocation, uv will verify that the lockfile is up-to-date with the
`pyproject.toml`, and that the environment is up-to-date with the lockfile, keeping your project
in-sync without the need for manual intervention. `uv run` guarantees that your command is run in a
consistent, locked environment.

The project environment can also be explicitly created with `uv sync`, e.g., for use with editors.

!!! note

    When in projects, uv will prefer a `.venv` in the project directory and ignore the active
    environment as declared by the `VIRTUAL_ENV` variable by default. You can opt-in to using the
    active environment with the `--active` flag.

To learn more, see the
[project environment](../../concepts/projects/layout.md#the-project-environment) documentation.

## Next steps

Now that you've migrated to uv, take a look at the
[project concept](../../concepts/projects/index.md) page for more details about uv projects.

    ---
title: Building and publishing a package
description: A guide to using uv to build and publish Python packages to a package index, like PyPI.
---

# Building and publishing a package

uv supports building Python packages into source and binary distributions via `uv build` and
uploading them to a registry with `uv publish`.

## Preparing your project for packaging

Before attempting to publish your project, you'll want to make sure it's ready to be packaged for
distribution.

If your project does not include a `[build-system]` definition in the `pyproject.toml`, uv will not
build it by default. This means that your project may not be ready for distribution. Read more about
the effect of declaring a build system in the
[project concept](../concepts/projects/config.md#build-systems) documentation.

!!! note

    If you have internal packages that you do not want to be published, you can mark them as
    private:

    ```toml
    [project]
    classifiers = ["Private :: Do Not Upload"]
    ```

    This setting makes PyPI reject your uploaded package from publishing. It does not affect
    security or privacy settings on alternative registries.

    We also recommend only generating [per-project PyPI API tokens](https://pypi.org/help/#apitoken):
    Without a PyPI token matching the project, it can't be accidentally published.

## Building your package

Build your package with `uv build`:

```console
$ uv build
```

By default, `uv build` will build the project in the current directory, and place the built
artifacts in a `dist/` subdirectory.

Alternatively, `uv build <SRC>` will build the package in the specified directory, while
`uv build --package <PACKAGE>` will build the specified package within the current workspace.

!!! info

    By default, `uv build` respects `tool.uv.sources` when resolving build dependencies from the
    `build-system.requires` section of the `pyproject.toml`. 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`](https://github.com/pypa/build).

## Updating your version

The `uv version` command provides conveniences for updating the version of your package before you
publish it.
[See the project docs for reading your package's version](./projects.md#managing-version).

To update to an exact version, provide it as a positional argument:

```console
$ uv version 1.0.0
hello-world 0.7.0 => 1.0.0
```

To preview the change without updating the `pyproject.toml`, use the `--dry-run` flag:

```console
$ uv version 2.0.0 --dry-run
hello-world 1.0.0 => 2.0.0
$ uv version
hello-world 1.0.0
```

To increase the version of your package semantics, use the `--bump` option:

```console
$ uv version --bump minor
hello-world 1.2.3 => 1.3.0
```

The `--bump` option supports the following common version components: `major`, `minor`, `patch`,
`stable`, `alpha`, `beta`, `rc`, `post`, and `dev`. When provided more than once, the components
will be applied in order, from largest (`major`) to smallest (`dev`).

To move from a stable to pre-release version, bump one of the major, minor, or patch components in
addition to the pre-release component:

```console
$ uv version --bump patch --bump beta
hello-world 1.3.0 => 1.3.1b1
$ uv version --bump major --bump alpha
hello-world 1.3.0 => 2.0.0a1
```

When moving from a pre-release to a new pre-release version, just bump the relevant pre-release
component:

```console
uv version --bump beta
hello-world 1.3.0b1 => 1.3.1b2
```

When moving from a pre-release to a stable version, the `stable` option can be used to clear the
pre-release component:

```console
uv version --bump stable
hello-world 1.3.1b2 => 1.3.1
```

!!! info

    By default, when `uv version` modifies the project it will perform a lock and sync. To
    prevent locking and syncing, use `--frozen`, or,  to just prevent syncing, use `--no-sync`.

## Publishing your package

!!! note

    A complete guide to publishing from GitHub Actions to PyPI can be found in the
    [GitHub Guide](integration/github.md#publishing-to-pypi)

Publish your package with `uv publish`:

```console
$ uv publish
```

Set a PyPI token with `--token` or `UV_PUBLISH_TOKEN`, or set a username with `--username` or
`UV_PUBLISH_USERNAME` and password with `--password` or `UV_PUBLISH_PASSWORD`. For publishing to
PyPI from GitHub Actions or another Trusted Publisher, you don't need to set any credentials.
Instead,
[add a trusted publisher to the PyPI project](https://docs.pypi.org/trusted-publishers/adding-a-publisher/).

!!! note

    PyPI does not support publishing with username and password anymore, instead you need to
    generate a token. Using a token is equivalent to setting `--username __token__` and using the
    token as password.

If you're using a custom index through `[[tool.uv.index]]`, add `publish-url` and use
`uv publish --index <name>`. For example:

```toml
[[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
publish-url = "https://test.pypi.org/legacy/"
explicit = true
```

!!! note

    When using `uv publish --index <name>`, the `pyproject.toml` must be present, i.e., you need to
    have a checkout step in a publish CI job.

Even though `uv publish` retries failed uploads, it can happen that publishing fails in the middle,
with some files uploaded and some files still missing. With PyPI, you can retry the exact same
command, existing identical files will be ignored. With other registries, use
`--check-url <index url>` with the index URL (not the publishing URL) the packages belong to. When
using `--index`, the index URL is used as check URL. uv will skip uploading files that are identical
to files in the registry, and it will also handle raced parallel uploads. Note that existing files
need to match exactly with those previously uploaded to the registry, this avoids accidentally
publishing source distribution and wheels with different contents for the same version.

## Installing your package

Test that the package can be installed and imported with `uv run`:

```console
$ uv run --with <PACKAGE> --no-project -- python -c "import <PACKAGE>"
```

The `--no-project` flag is used to avoid installing the package from your local project directory.

!!! tip

    If you have recently installed the package, you may need to include the
    `--refresh-package <PACKAGE>` option to avoid using a cached version of the package.

## Next steps

To learn more about publishing packages, check out the
[PyPA guides](https://packaging.python.org/en/latest/guides/section-build-and-publish/) on building
and publishing.

Or, read on for [guides](./integration/index.md) on integrating uv with other software.

    ---
title: Working on projects
description:
  A guide to using uv to create and manage Python projects, including adding dependencies, running
  commands, and building publishable distributions.
---

# Working on projects

uv supports managing Python projects, which define their dependencies in a `pyproject.toml` file.

## Creating a new project

You can create a new Python project using the `uv init` command:

```console
$ uv init hello-world
$ cd hello-world
```

Alternatively, you can initialize a project in the working directory:

```console
$ mkdir hello-world
$ cd hello-world
$ uv init
```

uv will create the following files:

```text
├── .gitignore
├── .python-version
├── README.md
├── main.py
└── pyproject.toml
```

The `main.py` file contains a simple "Hello world" program. Try it out with `uv run`:

```console
$ uv run main.py
Hello from hello-world!
```

## Project structure

A project consists of a few important parts that work together and allow uv to manage your project.
In addition to the files created by `uv init`, uv will create a virtual environment and `uv.lock`
file in the root of your project the first time you run a project command, i.e., `uv run`,
`uv sync`, or `uv lock`.

A complete listing would look like:

```text
.
├── .venv
│   ├── bin
│   ├── lib
│   └── pyvenv.cfg
├── .python-version
├── README.md
├── main.py
├── pyproject.toml
└── uv.lock
```

### `pyproject.toml`

The `pyproject.toml` contains metadata about your project:

```toml title="pyproject.toml"
[project]
name = "hello-world"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
dependencies = []
```

You'll use this file to specify dependencies, as well as details about the project such as its
description or license. You can edit this file manually, or use commands like `uv add` and
`uv remove` to manage your project from the terminal.

!!! tip

    See the official [`pyproject.toml` guide](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/)
    for more details on getting started with the `pyproject.toml` format.

You'll also use this file to specify uv [configuration options](../concepts/configuration-files.md)
in a [`[tool.uv]`](../reference/settings.md) section.

### `.python-version`

The `.python-version` file contains the project's default Python version. This file tells uv which
Python version to use when creating the project's virtual environment.

### `.venv`

The `.venv` folder contains your project's virtual environment, a Python environment that is
isolated from the rest of your system. This is where uv will install your project's dependencies.

See the [project environment](../concepts/projects/layout.md#the-project-environment) documentation
for more details.

### `uv.lock`

`uv.lock` is a cross-platform lockfile that contains exact information about your project's
dependencies. Unlike the `pyproject.toml` which is used to specify the broad requirements of your
project, the lockfile contains the exact resolved versions that are installed in the project
environment. This file should be checked into version control, allowing for consistent and
reproducible installations across machines.

`uv.lock` is a human-readable TOML file but is managed by uv and should not be edited manually.

See the [lockfile](../concepts/projects/layout.md#the-lockfile) documentation for more details.

## Managing dependencies

You can add dependencies to your `pyproject.toml` with the `uv add` command. This will also update
the lockfile and project environment:

```console
$ uv add requests
```

You can also specify version constraints or alternative sources:

```console
$ # Specify a version constraint
$ uv add 'requests==2.31.0'

$ # Add a git dependency
$ uv add git+https://github.com/psf/requests
```

If you're migrating from a `requirements.txt` file, you can use `uv add` with the `-r` flag to add
all dependencies from the file:

```console
$ # Add all dependencies from `requirements.txt`.
$ uv add -r requirements.txt -c constraints.txt
```

To remove a package, you can use `uv remove`:

```console
$ uv remove requests
```

To upgrade a package, run `uv lock` with the `--upgrade-package` flag:

```console
$ uv lock --upgrade-package requests
```

The `--upgrade-package` flag will attempt to update the specified package to the latest compatible
version, while keeping the rest of the lockfile intact.

See the documentation on [managing dependencies](../concepts/projects/dependencies.md) for more
details.

## Viewing your version

The `uv version` command can be used to read your package's version.

To get the version of your package, run `uv version`:

```console
$ uv version
hello-world 0.7.0
```

To get the version without the package name, use the `--short` option:

```console
$ uv version --short
0.7.0
```

To get version information in a JSON format, use the `--output-format json` option:

```console
$ uv version --output-format json
{
    "package_name": "hello-world",
    "version": "0.7.0",
    "commit_info": null
}
```

See the [publishing guide](./package.md#updating-your-version) for details on updating your package
version.

## Running commands

`uv run` can be used to run arbitrary scripts or commands in your project environment.

Prior to every `uv run` invocation, uv will verify that the lockfile is up-to-date with the
`pyproject.toml`, and that the environment is up-to-date with the lockfile, keeping your project
in-sync without the need for manual intervention. `uv run` guarantees that your command is run in a
consistent, locked environment.

For example, to use `flask`:

```console
$ uv add flask
$ uv run -- flask run -p 3000
```

Or, to run a script:

```python title="example.py"
# Require a project dependency
import flask

print("hello world")
```

```console
$ uv run example.py
```

Alternatively, you can use `uv sync` to manually update the environment then activate it before
executing a command:

=== "macOS and Linux"

    ```console
    $ uv sync
    $ source .venv/bin/activate
    $ flask run -p 3000
    $ python example.py
    ```

=== "Windows"

    ```pwsh-session
    PS> uv sync
    PS> .venv\Scripts\activate
    PS> flask run -p 3000
    PS> python example.py
    ```

!!! note

    The virtual environment must be active to run scripts and commands in the project without `uv run`. Virtual environment activation differs per shell and platform.

See the documentation on [running commands and scripts](../concepts/projects/run.md) in projects for
more details.

## Building distributions

`uv build` can be used to build source distributions and binary distributions (wheel) for your
project.

By default, `uv build` will build the project in the current directory, and place the built
artifacts in a `dist/` subdirectory:

```console
$ uv build
$ ls dist/
hello-world-0.1.0-py3-none-any.whl
hello-world-0.1.0.tar.gz
```

See the documentation on [building projects](../concepts/projects/build.md) for more details.

## Next steps

To learn more about working on projects with uv, see the
[projects concept](../concepts/projects/index.md) page and the
[command reference](../reference/cli.md#uv).

Or, read on to learn how to [build and publish your project to a package index](./package.md).

    ---
title: Running scripts
description:
  A guide to using uv to run Python scripts, including support for inline dependency metadata,
  reproducible scripts, and more.
---

# Running scripts

A Python script is a file intended for standalone execution, e.g., with `python <script>.py`. Using
uv to execute scripts ensures that script dependencies are managed without manually managing
environments.

!!! note

    If you are not familiar with Python environments: every Python installation has an environment
    that packages can be installed in. Typically, creating [_virtual_ environments](https://docs.python.org/3/library/venv.html) is recommended to
    isolate packages required by each script. uv automatically manages virtual environments for you
    and prefers a [declarative](#declaring-script-dependencies) approach to dependencies.

## Running a script without dependencies

If your script has no dependencies, you can execute it with `uv run`:

```python title="example.py"
print("Hello world")
```

```console
$ uv run example.py
Hello world
```

<!-- TODO(zanieb): Once we have a `python` shim, note you can execute it with `python` here -->

Similarly, if your script depends on a module in the standard library, there's nothing more to do:

```python title="example.py"
import os

print(os.path.expanduser("~"))
```

```console
$ uv run example.py
/Users/astral
```

Arguments may be provided to the script:

```python title="example.py"
import sys

print(" ".join(sys.argv[1:]))
```

```console
$ uv run example.py test
test

$ uv run example.py hello world!
hello world!
```

Additionally, your script can be read directly from stdin:

```console
$ echo 'print("hello world!")' | uv run -
```

Or, if your shell supports [here-documents](https://en.wikipedia.org/wiki/Here_document):

```bash
uv run - <<EOF
print("hello world!")
EOF
```

Note that if you use `uv run` in a _project_, i.e., a directory with a `pyproject.toml`, it will
install the current project before running the script. If your script does not depend on the
project, use the `--no-project` flag to skip this:

```console
$ # Note: the `--no-project` flag must be provided _before_ the script name.
$ uv run --no-project example.py
```

See the [projects guide](./projects.md) for more details on working in projects.

## Running a script with dependencies

When your script requires other packages, they must be installed into the environment that the
script runs in. uv prefers to create these environments on-demand instead of using a long-lived
virtual environment with manually managed dependencies. This requires explicit declaration of
dependencies that are required for the script. Generally, it's recommended to use a
[project](./projects.md) or [inline metadata](#declaring-script-dependencies) to declare
dependencies, but uv supports requesting dependencies per invocation as well.

For example, the following script requires `rich`.

```python title="example.py"
import time
from rich.progress import track

for i in track(range(20), description="For example:"):
    time.sleep(0.05)
```

If executed without specifying a dependency, this script will fail:

```console
$ uv run --no-project example.py
Traceback (most recent call last):
  File "/Users/astral/example.py", line 2, in <module>
    from rich.progress import track
ModuleNotFoundError: No module named 'rich'
```

Request the dependency using the `--with` option:

```console
$ uv run --with rich example.py
For example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:01
```

Constraints can be added to the requested dependency if specific versions are needed:

```console
$ uv run --with 'rich>12,<13' example.py
```

Multiple dependencies can be requested by repeating with `--with` option.

Note that if `uv run` is used in a _project_, these dependencies will be included _in addition_ to
the project's dependencies. To opt-out of this behavior, use the `--no-project` flag.

## Creating a Python script

Python recently added a standard format for
[inline script metadata](https://packaging.python.org/en/latest/specifications/inline-script-metadata/#inline-script-metadata).
It allows for selecting Python versions and defining dependencies. Use `uv init --script` to
initialize scripts with the inline metadata:

```console
$ uv init --script example.py --python 3.12
```

## Declaring script dependencies

The inline metadata format allows the dependencies for a script to be declared in the script itself.

uv supports adding and updating inline script metadata for you. Use `uv add --script` to declare the
dependencies for the script:

```console
$ uv add --script example.py 'requests<3' 'rich'
```

This will add a `script` section at the top of the script declaring the dependencies using TOML:

```python title="example.py"
# /// script
# dependencies = [
#   "requests<3",
#   "rich",
# ]
# ///

import requests
from rich.pretty import pprint

resp = requests.get("https://peps.python.org/api/peps.json")
data = resp.json()
pprint([(k, v["title"]) for k, v in data.items()][:10])
```

uv will automatically create an environment with the dependencies necessary to run the script, e.g.:

```console
$ uv run example.py
[
│   ('1', 'PEP Purpose and Guidelines'),
│   ('2', 'Procedure for Adding New Modules'),
│   ('3', 'Guidelines for Handling Bug Reports'),
│   ('4', 'Deprecation of Standard Modules'),
│   ('5', 'Guidelines for Language Evolution'),
│   ('6', 'Bug Fix Releases'),
│   ('7', 'Style Guide for C Code'),
│   ('8', 'Style Guide for Python Code'),
│   ('9', 'Sample Plaintext PEP Template'),
│   ('10', 'Voting Guidelines')
]
```

!!! important

    When using inline script metadata, even if `uv run` is [used in a _project_](../concepts/projects/run.md), the project's dependencies will be ignored. The `--no-project` flag is not required.

uv also respects Python version requirements:

```python title="example.py"
# /// script
# requires-python = ">=3.12"
# dependencies = []
# ///

# Use some syntax added in Python 3.12
type Point = tuple[float, float]
print(Point)
```

!!! note

    The `dependencies` field must be provided even if empty.

`uv run` will search for and use the required Python version. The Python version will download if it
is not installed — see the documentation on [Python versions](../concepts/python-versions.md) for
more details.

## Using a shebang to create an executable file

A shebang can be added to make a script executable without using `uv run` — this makes it easy to
run scripts that are on your `PATH` or in the current folder.

For example, create a file called `greet` with the following contents

```python title="greet"
#!/usr/bin/env -S uv run --script

print("Hello, world!")
```

Ensure that your script is executable, e.g., with `chmod +x greet`, then run the script:

```console
$ ./greet
Hello, world!
```

Declaration of dependencies is also supported in this context, for example:

```python title="example"
#!/usr/bin/env -S uv run --script
#
# /// script
# requires-python = ">=3.12"
# dependencies = ["httpx"]
# ///

import httpx

print(httpx.get("https://example.com"))
```

## Using alternative package indexes

If you wish to use an alternative [package index](../concepts/indexes.md) to resolve dependencies,
you can provide the index with the `--index` option:

```console
$ uv add --index "https://example.com/simple" --script example.py 'requests<3' 'rich'
```

This will include the package data in the inline metadata:

```python
# [[tool.uv.index]]
# url = "https://example.com/simple"
```

If you require authentication to access the package index, then please refer to the
[package index](../concepts/indexes.md) documentation.

## Locking dependencies

uv supports locking dependencies for PEP 723 scripts using the `uv.lock` file format. Unlike with
projects, scripts must be explicitly locked using `uv lock`:

```console
$ uv lock --script example.py
```

Running `uv lock --script` will create a `.lock` file adjacent to the script (e.g.,
`example.py.lock`).

Once locked, subsequent operations like `uv run --script`, `uv add --script`, `uv export --script`,
and `uv tree --script` will reuse the locked dependencies, updating the lockfile if necessary.

If no such lockfile is present, commands like `uv export --script` will still function as expected,
but will not create a lockfile.

## Improving reproducibility

In addition to locking dependencies, uv supports an `exclude-newer` field in the `tool.uv` section
of inline script metadata to limit uv to only considering distributions released before a specific
date. This is useful for improving the reproducibility of your script when run at a later point in
time.

The date must be specified as an [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html) timestamp
(e.g., `2006-12-02T02:07:43Z`).

```python title="example.py"
# /// script
# dependencies = [
#   "requests",
# ]
# [tool.uv]
# exclude-newer = "2023-10-16T00:00:00Z"
# ///

import requests

print(requests.__version__)
```

## Using different Python versions

uv allows arbitrary Python versions to be requested on each script invocation, for example:

```python title="example.py"
import sys

print(".".join(map(str, sys.version_info[:3])))
```

```console
$ # Use the default Python version, may differ on your machine
$ uv run example.py
3.12.6
```

```console
$ # Use a specific Python version
$ uv run --python 3.10 example.py
3.10.15
```

See the [Python version request](../concepts/python-versions.md#requesting-a-version) documentation
for more details on requesting Python versions.

## Using GUI scripts

On Windows `uv` will run your script ending with `.pyw` extension using `pythonw`:

```python title="example.pyw"
from tkinter import Tk, ttk

root = Tk()
root.title("uv")
frm = ttk.Frame(root, padding=10)
frm.grid()
ttk.Label(frm, text="Hello World").grid(column=0, row=0)
root.mainloop()
```

```console
PS> uv run example.pyw
```

![Run Result](../assets/uv_gui_script_hello_world.png){: style="height:50px;width:150px"}

Similarly, it works with dependencies as well:

```python title="example_pyqt.pyw"
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QGridLayout

app = QApplication(sys.argv)
widget = QWidget()
grid = QGridLayout()

text_label = QLabel()
text_label.setText("Hello World!")
grid.addWidget(text_label)

widget.setLayout(grid)
widget.setGeometry(100, 100, 200, 50)
widget.setWindowTitle("uv")
widget.show()
sys.exit(app.exec_())
```

```console
PS> uv run --with PyQt5 example_pyqt.pyw
```

![Run Result](../assets/uv_gui_script_hello_world_pyqt.png){: style="height:50px;width:150px"}

## Next steps

To learn more about `uv run`, see the [command reference](../reference/cli.md#uv-run).

Or, read on to learn how to [run and install tools](./tools.md) with uv.

    ---
title: Using tools
description:
  A guide to using uv to run tools published as Python packages, including one-off invocations with
  uvx, requesting specific tool versions, installing tools, upgrading tools, and more.
---

# Using tools

Many Python packages provide applications that can be used as tools. uv has specialized support for
easily invoking and installing tools.

## Running tools

The `uvx` command invokes a tool without installing it.

For example, to run `ruff`:

```console
$ uvx ruff
```

!!! note

    This is exactly equivalent to:

    ```console
    $ uv tool run ruff
    ```

    `uvx` is provided as an alias for convenience.

Arguments can be provided after the tool name:

```console
$ uvx pycowsay hello from uv

  -------------
< hello from uv >
  -------------
   \   ^__^
    \  (oo)\_______
       (__)\       )\/\
           ||----w |
           ||     ||

```

Tools are installed into temporary, isolated environments when using `uvx`.

!!! note

    If you are running a tool in a [_project_](../concepts/projects/index.md) and the tool requires that
    your project is installed, e.g., when using `pytest` or `mypy`, you'll want to use
    [`uv run`](./projects.md#running-commands) instead of `uvx`. Otherwise, the tool will be run in
    a virtual environment that is isolated from your project.

    If your project has a flat structure, e.g., instead of using a `src` directory for modules,
    the project itself does not need to be installed and `uvx` is fine. In this case, using
    `uv run` is only beneficial if you want to pin the version of the tool in the project's
    dependencies.

## Commands with different package names

When `uvx ruff` is invoked, uv installs the `ruff` package which provides the `ruff` command.
However, sometimes the package and command names differ.

The `--from` option can be used to invoke a command from a specific package, e.g., `http` which is
provided by `httpie`:

```console
$ uvx --from httpie http
```

## Requesting specific versions

To run a tool at a specific version, use `command@<version>`:

```console
$ uvx ruff@0.3.0 check
```

To run a tool at the latest version, use `command@latest`:

```console
$ uvx ruff@latest check
```

The `--from` option can also be used to specify package versions, as above:

```console
$ uvx --from 'ruff==0.3.0' ruff check
```

Or, to constrain to a range of versions:

```console
$ uvx --from 'ruff>0.2.0,<0.3.0' ruff check
```

Note the `@` syntax cannot be used for anything other than an exact version.

## Requesting extras

The `--from` option can be used to run a tool with extras:

```console
$ uvx --from 'mypy[faster-cache,reports]' mypy --xml-report mypy_report
```

This can also be combined with version selection:

```console
$ uvx --from 'mypy[faster-cache,reports]==1.13.0' mypy --xml-report mypy_report
```

## Requesting different sources

The `--from` option can also be used to install from alternative sources.

For example, to pull from git:

```console
$ uvx --from git+https://github.com/httpie/cli httpie
```

You can also pull the latest commit from a specific named branch:

```console
$ uvx --from git+https://github.com/httpie/cli@master httpie
```

Or pull a specific tag:

```console
$ uvx --from git+https://github.com/httpie/cli@3.2.4 httpie
```

Or even a specific commit:

```console
$ uvx --from git+https://github.com/httpie/cli@2843b87 httpie
```

## Commands with plugins

Additional dependencies can be included, e.g., to include `mkdocs-material` when running `mkdocs`:

```console
$ uvx --with mkdocs-material mkdocs --help
```

## Installing tools

If a tool is used often, it is useful to install it to a persistent environment and add it to the
`PATH` instead of invoking `uvx` repeatedly.

!!! tip

    `uvx` is a convenient alias for `uv tool run`. All of the other commands for interacting with
    tools require the full `uv tool` prefix.

To install `ruff`:

```console
$ uv tool install ruff
```

When a tool is installed, its executables are placed in a `bin` directory in the `PATH` which allows
the tool to be run without uv. If it's not on the `PATH`, a warning will be displayed and
`uv tool update-shell` can be used to add it to the `PATH`.

After installing `ruff`, it should be available:

```console
$ ruff --version
```

Unlike `uv pip install`, installing a tool does not make its modules available in the current
environment. For example, the following command will fail:

```console
$ python -c "import ruff"
```

This isolation is important for reducing interactions and conflicts between dependencies of tools,
scripts, and projects.

Unlike `uvx`, `uv tool install` operates on a _package_ and will install all executables provided by
the tool.

For example, the following will install the `http`, `https`, and `httpie` executables:

```console
$ uv tool install httpie
```

Additionally, package versions can be included without `--from`:

```console
$ uv tool install 'httpie>0.1.0'
```

And, similarly, for package sources:

```console
$ uv tool install git+https://github.com/httpie/cli
```

As with `uvx`, installations can include additional packages:

```console
$ uv tool install mkdocs --with mkdocs-material
```

Multiple related executables can be installed together in the same tool environment, using the
`--with-executables-from` flag. For example, the following will install the executables from
`ansible`, plus those ones provided by `ansible-core` and `ansible-lint`:

```console
$ uv tool install --with-executables-from ansible-core,ansible-lint ansible
```

## Upgrading tools

To upgrade a tool, use `uv tool upgrade`:

```console
$ uv tool upgrade ruff
```

Tool upgrades will respect the version constraints provided when installing the tool. For example,
`uv tool install ruff >=0.3,<0.4` followed by `uv tool upgrade ruff` will upgrade Ruff to the latest
version in the range `>=0.3,<0.4`.

To instead replace the version constraints, re-install the tool with `uv tool install`:

```console
$ uv tool install ruff>=0.4
```

To instead upgrade all tools:

```console
$ uv tool upgrade --all
```

## Requesting Python versions

By default, uv will use your default Python interpreter (the first it finds) when running,
installing, or upgrading tools. You can specify the Python interpreter to use with the `--python`
option.

For example, to request a specific Python version when running a tool:

```console
$ uvx --python 3.10 ruff
```

Or, when installing a tool:

```console
$ uv tool install --python 3.10 ruff
```

Or, when upgrading a tool:

```console
$ uv tool upgrade --python 3.10 ruff
```

For more details on requesting Python versions, see the
[Python version](../concepts/python-versions.md#requesting-a-version) concept page.

## Legacy Windows Scripts

Tools also support running
[legacy setuptools scripts](https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#scripts).
These scripts are available via `$(uv tool dir)\<tool-name>\Scripts` when installed.

Currently only legacy scripts with the `.ps1`, `.cmd`, and `.bat` extensions are supported.

For example, below is an example running a Command Prompt script.

```console
$ uv tool run --from nuitka==2.6.7 nuitka.cmd --version
```

In addition, you don't need to specify the extension. `uvx` will automatically look for files ending
in `.ps1`, `.cmd`, and `.bat` in that order of execution on your behalf.

```console
$ uv tool run --from nuitka==2.6.7 nuitka --version
```

## Next steps

To learn more about managing tools with uv, see the [Tools concept](../concepts/tools.md) page and
the [command reference](../reference/cli.md#uv-tool).

Or, read on to learn how to [work on projects](./projects.md).

    # uv

An extremely fast Python package and project manager, written in Rust.

<p align="center">
  <img alt="Shows a bar chart with benchmark results." src="https://github.com/astral-sh/uv/assets/1309177/629e59c0-9c6e-4013-9ad4-adb2bcf5080d#only-light">
</p>

<p align="center">
  <img alt="Shows a bar chart with benchmark results." src="https://github.com/astral-sh/uv/assets/1309177/03aa9163-1c79-4a87-a31d-7a9311ed9310#only-dark">
</p>

<p align="center">
  <i>Installing <a href="https://trio.readthedocs.io/">Trio</a>'s dependencies with a warm cache.</i>
</p>

## Highlights

- 🚀 A single tool to replace `pip`, `pip-tools`, `pipx`, `poetry`, `pyenv`, `twine`, `virtualenv`,
  and more.
- ⚡️ [10-100x faster](https://github.com/astral-sh/uv/blob/main/BENCHMARKS.md) than `pip`.
- 🗂️ Provides [comprehensive project management](#projects), with a
  [universal lockfile](./concepts/projects/layout.md#the-lockfile).
- ❇️ [Runs scripts](#scripts), with support for
  [inline dependency metadata](./guides/scripts.md#declaring-script-dependencies).
- 🐍 [Installs and manages](#python-versions) Python versions.
- 🛠️ [Runs and installs](#tools) tools published as Python packages.
- 🔩 Includes a [pip-compatible interface](#the-pip-interface) for a performance boost with a
  familiar CLI.
- 🏢 Supports Cargo-style [workspaces](./concepts/projects/workspaces.md) for scalable projects.
- 💾 Disk-space efficient, with a [global cache](./concepts/cache.md) for dependency deduplication.
- ⏬ Installable without Rust or Python via `curl` or `pip`.
- 🖥️ Supports macOS, Linux, and Windows.

uv is backed by [Astral](https://astral.sh), the creators of
[Ruff](https://github.com/astral-sh/ruff).

## Installation

Install uv with our official standalone installer:

=== "macOS and Linux"

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

=== "Windows"

    ```pwsh-session
    PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
    ```

Then, check out the [first steps](./getting-started/first-steps.md) or read on for a brief overview.

!!! tip

    uv may also be installed with pip, Homebrew, and more. See all of the methods on the
    [installation page](./getting-started/installation.md).

## Projects

uv manages project dependencies and environments, with support for lockfiles, workspaces, and more,
similar to `rye` or `poetry`:

```console
$ uv init example
Initialized project `example` at `/home/user/example`

$ cd example

$ uv add ruff
Creating virtual environment at: .venv
Resolved 2 packages in 170ms
   Built example @ file:///home/user/example
Prepared 2 packages in 627ms
Installed 2 packages in 1ms
 + example==0.1.0 (from file:///home/user/example)
 + ruff==0.5.4

$ uv run ruff check
All checks passed!

$ uv lock
Resolved 2 packages in 0.33ms

$ uv sync
Resolved 2 packages in 0.70ms
Audited 1 package in 0.02ms
```

See the [project guide](./guides/projects.md) to get started.

uv also supports building and publishing projects, even if they're not managed with uv. See the
[packaging guide](./guides/package.md) to learn more.

## Scripts

uv manages dependencies and environments for single-file scripts.

Create a new script and add inline metadata declaring its dependencies:

```console
$ echo 'import requests; print(requests.get("https://astral.sh"))' > example.py

$ uv add --script example.py requests
Updated `example.py`
```

Then, run the script in an isolated virtual environment:

```console
$ uv run example.py
Reading inline script metadata from: example.py
Installed 5 packages in 12ms
<Response [200]>
```

See the [scripts guide](./guides/scripts.md) to get started.

## Tools

uv executes and installs command-line tools provided by Python packages, similar to `pipx`.

Run a tool in an ephemeral environment using `uvx` (an alias for `uv tool run`):

```console
$ uvx pycowsay 'hello world!'
Resolved 1 package in 167ms
Installed 1 package in 9ms
 + pycowsay==0.0.0.2
  """

  ------------
< hello world! >
  ------------
   \   ^__^
    \  (oo)\_______
       (__)\       )\/\
           ||----w |
           ||     ||
```

Install a tool with `uv tool install`:

```console
$ uv tool install ruff
Resolved 1 package in 6ms
Installed 1 package in 2ms
 + ruff==0.5.4
Installed 1 executable: ruff

$ ruff --version
ruff 0.5.4
```

See the [tools guide](./guides/tools.md) to get started.

## Python versions

uv installs Python and allows quickly switching between versions.

Install multiple Python versions:

```console
$ uv python install 3.10 3.11 3.12
Searching for Python versions matching: Python 3.10
Searching for Python versions matching: Python 3.11
Searching for Python versions matching: Python 3.12
Installed 3 versions in 3.42s
 + cpython-3.10.14-macos-aarch64-none
 + cpython-3.11.9-macos-aarch64-none
 + cpython-3.12.4-macos-aarch64-none
```

Download Python versions as needed:

```console
$ uv venv --python 3.12.0
Using CPython 3.12.0
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate

$ uv run --python pypy@3.8 -- python
Python 3.8.16 (a9dbdca6fc3286b0addd2240f11d97d8e8de187a, Dec 29 2022, 11:45:30)
[PyPy 7.3.11 with GCC Apple LLVM 13.1.6 (clang-1316.0.21.2.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>>
```

Use a specific Python version in the current directory:

```console
$ uv python pin 3.11
Pinned `.python-version` to `3.11`
```

See the [installing Python guide](./guides/install-python.md) to get started.

## The pip interface

uv provides a drop-in replacement for common `pip`, `pip-tools`, and `virtualenv` commands.

uv extends their interfaces with advanced features, such as dependency version overrides,
platform-independent resolutions, reproducible resolutions, alternative resolution strategies, and
more.

Migrate to uv without changing your existing workflows — and experience a 10-100x speedup — with the
`uv pip` interface.

Compile requirements into a platform-independent requirements file:

```console
$ uv pip compile docs/requirements.in \
   --universal \
   --output-file docs/requirements.txt
Resolved 43 packages in 12ms
```

Create a virtual environment:

```console
$ uv venv
Using CPython 3.12.3
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate
```

Install the locked requirements:

```console
$ uv pip sync docs/requirements.txt
Resolved 43 packages in 11ms
Installed 43 packages in 208ms
 + babel==2.15.0
 + black==24.4.2
 + certifi==2024.7.4
 ...
```

See the [pip interface documentation](./pip/index.md) to get started.

## Learn more

See the [first steps](./getting-started/first-steps.md) or jump straight to the
[guides](./guides/index.md) to start using uv.

    # Compatibility with `pip` and `pip-tools`

uv is designed as a drop-in replacement for common `pip` and `pip-tools` workflows.

Informally, the intent is such that existing `pip` and `pip-tools` users can switch to uv without
making meaningful changes to their packaging workflows; and, in most cases, swapping out
`pip install` for `uv pip install` should "just work".

However, uv is _not_ intended to be an _exact_ clone of `pip`, and the further you stray from common
`pip` workflows, the more likely you are to encounter differences in behavior. In some cases, those
differences may be known and intentional; in others, they may be the result of implementation
details; and in others, they may be bugs.

This document outlines the known differences between uv and `pip`, along with rationale,
workarounds, and a statement of intent for compatibility in the future.

## Configuration files and environment variables

uv does not read configuration files or environment variables that are specific to `pip`, like
`pip.conf` or `PIP_INDEX_URL`.

Reading configuration files and environment variables intended for other tools has a number of
drawbacks:

1. It requires bug-for-bug compatibility with the target tool, since users end up relying on bugs in
   the format, the parser, etc.
2. If the target tool _changes_ the format in some way, uv is then locked-in to changing it in
   equivalent ways.
3. If that configuration is versioned in some way, uv would need to know _which version_ of the
   target tool the user is expecting to use.
4. It prevents uv from introducing any settings or configuration that don't exist in the target
   tool, since otherwise `pip.conf` (or similar) would no longer be usable with `pip`.
5. It can lead to user confusion, since uv would be reading settings that don't actually affect its
   behavior, and many users may _not_ expect uv to read configuration files intended for other
   tools.

Instead, uv supports its own environment variables, like `UV_INDEX_URL`. uv also supports persistent
configuration in a `uv.toml` file or a `[tool.uv.pip]` section of `pyproject.toml`. For more
information, see [Configuration files](../concepts/configuration-files.md).

## Pre-release compatibility

By default, uv will accept pre-release versions during dependency resolution in two cases:

1. If the package is a direct dependency, and its version markers include a pre-release specifier
   (e.g., `flask>=2.0.0rc1`).
1. If _all_ published versions of a package are pre-releases.

If dependency resolution fails due to a transitive pre-release, uv will prompt the user to re-run
with `--prerelease allow`, to allow pre-releases for all dependencies.

Alternatively, you can add the transitive dependency to your `requirements.in` file with pre-release
specifier (e.g., `flask>=2.0.0rc1`) to opt in to pre-release support for that specific dependency.

In sum, uv needs to know upfront whether the resolver should accept pre-releases for a given
package. `pip`, meanwhile, _may_ respect pre-release identifiers in transitive dependencies
depending on the order in which the resolver encounters the relevant specifiers
([#1641](https://github.com/astral-sh/uv/issues/1641#issuecomment-1981402429)).

Pre-releases are
[notoriously difficult](https://pubgrub-rs-guide.netlify.app/limitations/prerelease_versions) to
model, and are a frequent source of bugs in packaging tools. Even `pip`, which is viewed as a
reference implementation, has a number of open questions around pre-release handling
([#12469](https://github.com/pypa/pip/issues/12469),
[#12470](https://github.com/pypa/pip/issues/12470),
[#40505](https://discuss.python.org/t/handling-of-pre-releases-when-backtracking/40505/20), etc.).
uv's pre-release handling is _intentionally_ limited and _intentionally_ requires user opt-in for
pre-releases, to ensure correctness.

In the future, uv _may_ support pre-release identifiers in transitive dependencies. However, it's
likely contingent on evolution in the Python packaging specifications. The existing PEPs
[do not cover "dependency resolution"](https://discuss.python.org/t/handling-of-pre-releases-when-backtracking/40505/17)
and are instead focused on behavior for a _single_ version specifier. As such, there are unresolved
questions around the correct and intended behavior for pre-releases in the packaging ecosystem more
broadly.

## Packages that exist on multiple indexes

In both uv and `pip`, users can specify multiple package indexes from which to search for the
available versions of a given package. However, uv and `pip` differ in how they handle packages that
exist on multiple indexes.

For example, imagine that a company publishes an internal version of `requests` on a private index
(`--extra-index-url`), but also allows installing packages from PyPI by default. In this case, the
private `requests` would conflict with the public [`requests`](https://pypi.org/project/requests/)
on PyPI.

When uv searches for a package across multiple indexes, it will iterate over the indexes in order
(preferring the `--extra-index-url` over the default index), and stop searching as soon as it finds
a match. This means that if a package exists on multiple indexes, uv will limit its candidate
versions to those present in the first index that contains the package.

`pip`, meanwhile, will combine the candidate versions from all indexes, and select the best version
from the combined set, though it makes
[no guarantees around the order](https://github.com/pypa/pip/issues/5045#issuecomment-369521345) in
which it searches indexes, and expects that packages are unique up to name and version, even across
indexes.

uv's behavior is such that if a package exists on an internal index, it should always be installed
from the internal index, and never from PyPI. The intent is to prevent "dependency confusion"
attacks, in which an attacker publishes a malicious package on PyPI with the same name as an
internal package, thus causing the malicious package to be installed instead of the internal
package. See, for example,
[the `torchtriton` attack](https://pytorch.org/blog/compromised-nightly-dependency/) from
December 2022.

As of v0.1.39, users can opt in to `pip`-style behavior for multiple indexes via the
`--index-strategy` command-line option, or the `UV_INDEX_STRATEGY` environment variable, which
supports the following values:

- `first-index` (default): Search for each package across all indexes, limiting the candidate
  versions to those present in the first index that contains the package, prioritizing the
  `--extra-index-url` indexes over the default index URL.
- `unsafe-first-match`: Search for each package across all indexes, but prefer the first index with
  a compatible version, even if newer versions are available on other indexes.
- `unsafe-best-match`: Search for each package across all indexes, and select the best version from
  the combined set of candidate versions.

While `unsafe-best-match` is the closest to `pip`'s behavior, it exposes users to the risk of
"dependency confusion" attacks.

uv also supports pinning packages to dedicated indexes (see:
[_Indexes_](../concepts/indexes.md#pinning-a-package-to-an-index)), such that a given package is
_always_ installed from a specific index.

## PEP 517 build isolation

uv uses [PEP 517](https://peps.python.org/pep-0517/) build isolation by default (akin to
`pip install --use-pep517`), following `pypa/build` and in anticipation of `pip` defaulting to PEP
517 builds in the future ([pypa/pip#9175](https://github.com/pypa/pip/issues/9175)).

If a package fails to install due to a missing build-time dependency, try using a newer version of
the package; if the problem persists, consider filing an issue with the package maintainer,
requesting that they update the packaging setup to declare the correct PEP 517 build-time
dependencies.

As an escape hatch, you can preinstall a package's build dependencies, then run `uv pip install`
with `--no-build-isolation`, as in:

```shell
uv pip install wheel && uv pip install --no-build-isolation biopython==1.77
```

For a list of packages that are known to fail under PEP 517 build isolation, see
[#2252](https://github.com/astral-sh/uv/issues/2252).

## Transitive URL dependencies

While uv includes first-class support for URL dependencies (e.g., `ruff @ https://...`), it differs
from pip in its handling of _transitive_ URL dependencies in two ways.

First, uv makes the assumption that non-URL dependencies do not introduce URL dependencies into the
resolution. In other words, it assumes that dependencies fetched from a registry do not themselves
depend on URLs. If a non-URL dependency _does_ introduce a URL dependency, uv will reject the URL
dependency during resolution. (Note that PyPI does not allow published packages to depend on URL
dependencies; other registries may be more permissive.)

Second, if a constraint (`--constraint`) or override (`--override`) is defined using a direct URL
dependency, and the constrained package has a direct URL dependency of its own, uv _may_ reject that
transitive direct URL dependency during resolution, if the URL isn't referenced elsewhere in the set
of input requirements.

If uv rejects a transitive URL dependency, the best course of action is to provide the URL
dependency as a direct dependency in the relevant `pyproject.toml` or `requirement.in` file, as the
above constraints do not apply to direct dependencies.

## Virtual environments by default

`uv pip install` and `uv pip sync` are designed to work with virtual environments by default.

Specifically, uv will always install packages into the currently active virtual environment, or
search for a virtual environment named `.venv` in the current directory or any parent directory
(even if it is not activated).

This differs from `pip`, which will install packages into a global environment if no virtual
environment is active, and will not search for inactive virtual environments.

In uv, you can install into non-virtual environments by providing a path to a Python executable via
the `--python /path/to/python` option, or via the `--system` flag, which installs into the first
Python interpreter found on the `PATH`, like `pip`.

In other words, uv inverts the default, requiring explicit opt-in to installing into the system
Python, which can lead to breakages and other complications, and should only be done in limited
circumstances.

For more, see
["Using arbitrary Python environments"](./environments.md#using-arbitrary-python-environments).

## Resolution strategy

For a given set of dependency specifiers, it's often the case that there is no single "correct" set
of packages to install. Instead, there are many valid sets of packages that satisfy the specifiers.

Neither `pip` nor uv make any guarantees about the _exact_ set of packages that will be installed;
only that the resolution will be consistent, deterministic, and compliant with the specifiers. As
such, in some cases, `pip` and uv will yield different resolutions; however, both resolutions
_should_ be equally valid.

For example, consider:

```python title="requirements.in"
starlette
fastapi
```

At time of writing, the most recent `starlette` version is `0.37.2`, and the most recent `fastapi`
version is `0.110.0`. However, `fastapi==0.110.0` also depends on `starlette`, and introduces an
upper bound: `starlette>=0.36.3,<0.37.0`.

If a resolver prioritizes including the most recent version of `starlette`, it would need to use an
older version of `fastapi` that excludes the upper bound on `starlette`. In practice, this requires
falling back to `fastapi==0.1.17`:

```python title="requirements.txt"
# This file was autogenerated by uv via the following command:
#    uv pip compile requirements.in
annotated-types==0.6.0
    # via pydantic
anyio==4.3.0
    # via starlette
fastapi==0.1.17
idna==3.6
    # via anyio
pydantic==2.6.3
    # via fastapi
pydantic-core==2.16.3
    # via pydantic
sniffio==1.3.1
    # via anyio
starlette==0.37.2
    # via fastapi
typing-extensions==4.10.0
    # via
    #   pydantic
    #   pydantic-core
```

Alternatively, if a resolver prioritizes including the most recent version of `fastapi`, it would
need to use an older version of `starlette` that satisfies the upper bound. In practice, this
requires falling back to `starlette==0.36.3`:

```python title="requirements.txt"
# This file was autogenerated by uv via the following command:
#    uv pip compile requirements.in
annotated-types==0.6.0
    # via pydantic
anyio==4.3.0
    # via starlette
fastapi==0.110.0
idna==3.6
    # via anyio
pydantic==2.6.3
    # via fastapi
pydantic-core==2.16.3
    # via pydantic
sniffio==1.3.1
    # via anyio
starlette==0.36.3
    # via fastapi
typing-extensions==4.10.0
    # via
    #   fastapi
    #   pydantic
    #   pydantic-core
```

When uv resolutions differ from `pip` in undesirable ways, it's often a sign that the specifiers are
too loose, and that the user should consider tightening them. For example, in the case of
`starlette` and `fastapi`, the user could require `fastapi>=0.110.0`.

## `pip check`

At present, `uv pip check` will surface the following diagnostics:

- A package has no `METADATA` file, or the `METADATA` file can't be parsed.
- A package has a `Requires-Python` that doesn't match the Python version of the running
  interpreter.
- A package has a dependency on a package that isn't installed.
- A package has a dependency on a package that's installed, but at an incompatible version.
- Multiple versions of a package are installed in the virtual environment.

In some cases, `uv pip check` will surface diagnostics that `pip check` does not, and vice versa.
For example, unlike `uv pip check`, `pip check` will _not_ warn when multiple versions of a package
are installed in the current environment.

## `--user` and the `user` install scheme

uv does not support the `--user` flag, which installs packages based on the `user` install scheme.
Instead, we recommend the use of virtual environments to isolate package installations.

Additionally, pip will fall back to the `user` install scheme if it detects that the user does not
have write permissions to the target directory, as is the case on some systems when installing into
the system Python. uv does not implement any such fallback.

For more, see [#2077](https://github.com/astral-sh/uv/issues/2077).

## `--only-binary` enforcement

The `--only-binary` argument is used to restrict installation to pre-built binary distributions.
When `--only-binary :all:` is provided, both pip and uv will refuse to build source distributions
from PyPI and other registries.

However, when a dependency is provided as a direct URL (e.g., `uv pip install https://...`), pip
does _not_ enforce `--only-binary`, and will build source distributions for all such packages.

uv, meanwhile, _does_ enforce `--only-binary` for direct URL dependencies, with one exception: given
`uv pip install https://... --only-binary flask`, uv _will_ build the source distribution at the
given URL if it cannot infer the package name ahead of time, since uv can't determine whether the
package is "allowed" in such cases without building its metadata.

Both pip and uv allow editables requirements to be built and installed even when `--only-binary` is
provided. For example, `uv pip install -e . --only-binary :all:` is allowed.

## `--no-binary` enforcement

The `--no-binary` argument is used to restrict installation to source distributions. When
`--no-binary` is provided, uv will refuse to install pre-built binary distributions, but _will_
reuse any binary distributions that are already present in the local cache.

Additionally, and in contrast to pip, uv's resolver will still read metadata from pre-built binary
distributions when `--no-binary` is provided.

## `manylinux_compatible` enforcement

[PEP 600](https://peps.python.org/pep-0600/#package-installers) describes a mechanism through which
Python distributors can opt out of `manylinux` compatibility by defining a `manylinux_compatible`
function on the `_manylinux` standard library module.

uv respects `manylinux_compatible`, but only tests against the current glibc version, and applies
the return value of `manylinux_compatible` globally.

In other words, if `manylinux_compatible` returns `True`, uv will treat the system as
`manylinux`-compatible; if it returns `False`, uv will treat the system as `manylinux`-incompatible,
without calling `manylinux_compatible` for every glibc version.

This approach is not a complete implementation of the spec, but is compatible with common blanket
`manylinux_compatible` implementations like
[`no-manylinux`](https://pypi.org/project/no-manylinux/):

```python
from __future__ import annotations
manylinux1_compatible = False
manylinux2010_compatible = False
manylinux2014_compatible = False


def manylinux_compatible(*_, **__):  # PEP 600
    return False
```

## Bytecode compilation

Unlike `pip`, uv does not compile `.py` files to `.pyc` files during installation by default (i.e.,
uv does not create or populate `__pycache__` directories). To enable bytecode compilation during
installs, pass the `--compile-bytecode` flag to `uv pip install` or `uv pip sync`, or set the
`UV_COMPILE_BYTECODE` environment variable to `1`.

Skipping bytecode compilation can be undesirable in workflows; for example, we recommend enabling
bytecode compilation in [Docker builds](../guides/integration/docker.md) to improve startup times
(at the cost of increased build times).

As bytecode compilation suppresses various warnings issued by the Python interpreter, in rare cases
you may seen `SyntaxWarning` or `DeprecationWarning` messages when running Python code that was
installed with uv that do not appear when using `pip`. These are valid warnings, but are typically
hidden by the bytecode compilation process, and can either be ignored, fixed upstream, or similarly
suppressed by enabling bytecode compilation in uv.

## Strictness and spec enforcement

uv tends to be stricter than `pip`, and will often reject packages that `pip` would install. For
example, uv rejects HTML indexes with invalid URL fragments (see:
[PEP 503](https://peps.python.org/pep-0503/)), while `pip` will ignore such fragments.

In some cases, uv implements lenient behavior for popular packages that are known to have specific
spec compliance issues.

If uv rejects a package that `pip` would install due to a spec violation, the best course of action
is to first attempt to install a newer version of the package; and, if that fails, to report the
issue to the package maintainer.

## `pip` command-line options and subcommands

uv does not support the complete set of `pip`'s command-line options and subcommands, although it
does support a large subset.

Missing options and subcommands are prioritized based on user demand and the complexity of the
implementation, and tend to be tracked in individual issues. For example:

- [`--trusted-host`](https://github.com/astral-sh/uv/issues/1339)
- [`--user`](https://github.com/astral-sh/uv/issues/2077)

If you encounter a missing option or subcommand, please search the issue tracker to see if it has
already been reported, and if not, consider opening a new issue. Feel free to upvote any existing
issues to convey your interest.

## Registry authentication

uv does not support `pip`'s `auto` or `import` options for `--keyring-provider`. At present, only
the `subprocess` option is supported.

Unlike `pip`, uv does not enable keyring authentication by default.

Unlike `pip`, uv does not wait until a request returns an HTTP 401 before searching for
authentication. uv attaches authentication to all requests for hosts with credentials available.

## `egg` support

uv does not support features that are considered legacy or deprecated in `pip`. For example, uv does
not support `.egg`-style distributions.

However, uv does have partial support for (1) `.egg-info`-style distributions (which are
occasionally found in Docker images and Conda environments) and (2) legacy editable
`.egg-link`-style distributions.

Specifically, uv does not support installing new `.egg-info`- or `.egg-link`-style distributions,
but will respect any such existing distributions during resolution, list them with `uv pip list` and
`uv pip freeze`, and uninstall them with `uv pip uninstall`.

## Build constraints

When constraints are provided via `--constraint` (or `UV_CONSTRAINT`), uv will _not_ apply the
constraints when resolving build dependencies (i.e., to build a source distribution). Instead, build
constraints should be provided via the dedicated `--build-constraint` (or `UV_BUILD_CONSTRAINT`)
setting.

pip, meanwhile, applies constraints to build dependencies when specified via `PIP_CONSTRAINT`, but
not when provided via `--constraint` on the command line.

For example, to ensure that `setuptools 60.0.0` is used to build any packages with a build
dependency on `setuptools`, use `--build-constraint`, rather than `--constraint`.

## `pip compile` defaults

There are a few small but notable differences in the default behaviors of `pip compile` and
`pip-tools`.

By default, uv does not write the compiled requirements to an output file. Instead, uv requires that
the user specify an output file explicitly with the `-o` or `--output-file` option.

By default, uv strips extras when outputting the compiled requirements. In other words, uv defaults
to `--strip-extras`, while `pip-compile` defaults to `--no-strip-extras`. `pip-compile` is scheduled
to change this default in the next major release (v8.0.0), at which point both tools will default to
`--strip-extras`. To retain extras with uv, pass the `--no-strip-extras` flag to `uv pip compile`.

By default, uv does not write any index URLs to the output file, while `pip-compile` outputs any
`--index-url` or `--extra-index-url` that does not match the default (PyPI). To include index URLs
in the output file, pass the `--emit-index-url` flag to `uv pip compile`. Unlike `pip-compile`, uv
will include all index URLs when `--emit-index-url` is passed, including the default index URL.

## `requires-python` upper bounds

When evaluating `requires-python` ranges for dependencies, uv only considers lower bounds and
ignores upper bounds entirely. For example, `>=3.8, <4` is treated as `>=3.8`. Respecting upper
bounds on `requires-python` often leads to formally correct but practically incorrect resolutions,
as, e.g., resolvers will backtrack to the first published version that omits the upper bound (see:
[`Requires-Python` upper limits](https://discuss.python.org/t/requires-python-upper-limits/12663)).

## `requires-python` specifiers

When evaluating Python versions against `requires-python` specifiers, uv truncates the candidate
version to the major, minor, and patch components, ignoring (e.g.) pre-release and post-release
identifiers.

For example, a project that declares `requires-python: >=3.13` will accept Python 3.13.0b1. While
3.13.0b1 is not strictly greater than 3.13, it is greater than 3.13 when the pre-release identifier
is omitted.

While this is not strictly compliant with [PEP 440](https://peps.python.org/pep-0440/), it _is_
consistent with
[pip](https://github.com/pypa/pip/blob/24.1.1/src/pip/_internal/resolution/resolvelib/candidates.py#L540).

## Package priority

There are usually many possible solutions given a set of requirements, and a resolver must choose
between them. uv's resolver and pip's resolver have a different set of package priorities. While
both resolvers use the user-provided order as one of their priorities, pip has additional
[priorities](https://pip.pypa.io/en/stable/topics/more-dependency-resolution/#the-resolver-algorithm)
that uv does not have. Hence, uv is more likely to be affected by a change in user order than pip
is.

For example, `uv pip install foo bar` prioritizes newer versions of `foo` over `bar` and could
result in a different resolution than `uv pip install bar foo`. Similarly, this behavior applies to
the ordering of requirements in input files for `uv pip compile`.

    # Locking environments

Locking is to take a dependency, e.g., `ruff`, and write an exact version to use to a file. When
working with many dependencies, it is useful to lock the exact versions so the environment can be
reproduced. Without locking, the versions of dependencies could change over time, when using a
different tool, or across platforms.

## Locking requirements

uv allows dependencies to be locked in the `requirements.txt` format. It is recommended to use the
standard `pyproject.toml` to define dependencies, but other dependency formats are supported as
well. See the documentation on [declaring dependencies](dependencies.md) for more details on how to
define dependencies.

To lock dependencies declared in a `pyproject.toml`:

```console
$ uv pip compile pyproject.toml -o requirements.txt
```

Note by default the `uv pip compile` output is just displayed and `--output-file` / `-o` argument is
needed to write to a file.

To lock dependencies declared in a `requirements.in`:

```console
$ uv pip compile requirements.in -o requirements.txt
```

To lock dependencies declared in multiple files:

```console
$ uv pip compile pyproject.toml requirements-dev.in -o requirements-dev.txt
```

uv also supports legacy `setup.py` and `setup.cfg` formats. To lock dependencies declared in a
`setup.py`:

```console
$ uv pip compile setup.py -o requirements.txt
```

To lock dependencies from stdin, use `-`:

```console
$ echo "ruff" | uv pip compile -
```

To lock with optional dependencies enabled, e.g., the "foo" extra:

```console
$ uv pip compile pyproject.toml --extra foo
```

To lock with all optional dependencies enabled:

```console
$ uv pip compile pyproject.toml --all-extras
```

Note extras are not supported with the `requirements.in` format.

To lock a dependency group in the current project directory's `pyproject.toml`, for example the
group `foo`:

```console
$ uv pip compile --group foo
```

!!! important

    A `--group` flag has to be added to pip-tools' `pip compile`, [although they're considering it](https://github.com/jazzband/pip-tools/issues/2062). We expect to support whatever syntax and semantics they adopt.

To specify the project directory where groups should be sourced from:

```console
$ uv pip compile --project some/path/ --group foo --group bar
```

Alternatively, you can specify a path to a `pyproject.toml` for each group:

```console
$ uv pip compile --group some/path/pyproject.toml:foo --group other/pyproject.toml:bar
```

!!! note

    `--group` flags do not apply to other specified sources. For instance,
    `uv pip compile some/path/pyproject.toml --group foo` sources `foo`
    from `./pyproject.toml` and **not** `some/path/pyproject.toml`.

## Upgrading requirements

When using an output file, uv will consider the versions pinned in an existing output file. If a
dependency is pinned it will not be upgraded on a subsequent compile run. For example:

```console
$ echo "ruff==0.3.0" > requirements.txt
$ echo "ruff" | uv pip compile - -o requirements.txt
# This file was autogenerated by uv via the following command:
#    uv pip compile - -o requirements.txt
ruff==0.3.0
```

To upgrade a dependency, use the `--upgrade-package` flag:

```console
$ uv pip compile - -o requirements.txt --upgrade-package ruff
```

To upgrade all dependencies, there is an `--upgrade` flag.

## Syncing an environment

Dependencies can be installed directly from their definition files or from compiled
`requirements.txt` files with `uv pip install`. See the documentation on
[installing packages from files](packages.md#installing-packages-from-files) for more details.

When installing with `uv pip install`, packages that are already installed will not be removed
unless they conflict with the lockfile. This means that the environment can have dependencies that
aren't declared in the lockfile, which isn't great for reproducibility. To ensure the environment
exactly matches the lockfile, use `uv pip sync` instead.

To sync an environment with a `requirements.txt` file:

```console
$ uv pip sync requirements.txt
```

To sync an environment with a [PEP 751](https://peps.python.org/pep-0751/) `pylock.toml` file:

```console
$ uv pip sync pylock.toml
```

## Adding constraints

Constraints files are `requirements.txt`-like files that only control the _version_ of a requirement
that's installed. However, including a package in a constraints file will _not_ trigger the
installation of that package. Constraints can be used to add bounds to dependencies that are not
dependencies of the current project.

To define a constraint, define a bound for a package:

```python title="constraints.txt"
pydantic<2.0
```

To use a constraints file:

```console
$ uv pip compile requirements.in --constraint constraints.txt
```

Note that multiple constraints can be defined in each file and multiple files can be used.

uv will also read `constraint-dependencies` from the `pyproject.toml` at the workspace root, and
append them to those specified in the constraints file.

## Adding build constraints

Similar to `constraints`, but specifically for build-time dependencies, including those required
when building runtime dependencies.

Build constraint files are `requirements.txt`-like files that only control the _version_ of a
build-time requirement. However, including a package in a build constraints file will _not_ trigger
its installation at build time; instead, constraints apply only when the package is required as a
direct or transitive build-time dependency. Build constraints can be used to add bounds to
dependencies that are not explicitly declared as build-time dependencies of the current project.

For example, if a package defines its build dependencies as follows:

```toml title="pyproject.toml"
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
```

Build constraints could be used to ensure that a specific version of `setuptools` is used for every
package in the workspace:

```python title="build-constraints.txt"
setuptools==75.0.0
```

uv will also read `build-constraint-dependencies` from the `pyproject.toml` at the workspace root,
and append them to those specified in the build constraints file.

## Overriding dependency versions

Overrides files are `requirements.txt`-like files that force a specific version of a requirement to
be installed, regardless of the requirements declared by any constituent package, and regardless of
whether this would be considered an invalid resolution.

While constraints are _additive_, in that they're combined with the requirements of the constituent
packages, overrides are _absolute_, in that they completely replace the requirements of the
constituent packages.

Overrides are most often used to remove upper bounds from a transitive dependency. For example, if
`a` requires `c>=1.0,<2.0` and `b` requires `c>=2.0` and the current project requires `a` and `b`
then the dependencies cannot be resolved.

To define an override, define the new requirement for the problematic package:

```python title="overrides.txt"
c>=2.0
```

To use an overrides file:

```console
$ uv pip compile requirements.in --override overrides.txt
```

Now, resolution can succeed. However, note that if `a` is _correct_ that it does not support
`c>=2.0` then a runtime error will likely be encountered when using the packages.

Note that multiple overrides can be defined in each file and multiple files can be used.

    # Declaring dependencies

It is best practice to declare dependencies in a static file instead of modifying environments with
ad-hoc installations. Once dependencies are defined, they can be [locked](./compile.md) to create a
consistent, reproducible environment.

## Using `pyproject.toml`

The `pyproject.toml` file is the Python standard for defining configuration for a project.

To define project dependencies in a `pyproject.toml` file:

```toml title="pyproject.toml"
[project]
dependencies = [
  "httpx",
  "ruff>=0.3.0"
]
```

To define optional dependencies in a `pyproject.toml` file:

```toml title="pyproject.toml"
[project.optional-dependencies]
cli = [
  "rich",
  "click",
]
```

Each of the keys defines an "extra", which can be installed using the `--extra` and `--all-extras`
flags or `package[<extra>]` syntax. See the documentation on
[installing packages](./packages.md#installing-packages-from-files) for more details.

See the official
[`pyproject.toml` guide](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/) for
more details on getting started with a `pyproject.toml`.

## Using `requirements.in`

It is also common to use a lightweight `requirements.txt` format to declare the dependencies for the
project. Each requirement is defined on its own line. Commonly, this file is called
`requirements.in` to distinguish it from `requirements.txt` which is used for the locked
dependencies.

To define dependencies in a `requirements.in` file:

```python title="requirements.in"
httpx
ruff>=0.3.0
```

Optional dependencies groups are not supported in this format.

    # Using Python environments

Each Python installation has an environment that is active when Python is used. Packages can be
installed into an environment to make their modules available from your Python scripts. Generally,
it is considered best practice not to modify a Python installation's environment. This is especially
important for Python installations that come with the operating system which often manage the
packages themselves. A virtual environment is a lightweight way to isolate packages from a Python
installation's environment. Unlike `pip`, uv requires using a virtual environment by default.

## Creating a virtual environment

uv supports creating virtual environments, e.g., to create a virtual environment at `.venv`:

```console
$ uv venv
```

A specific name or path can be specified, e.g., to create a virtual environment at `my-name`:

```console
$ uv venv my-name
```

A Python version can be requested, e.g., to create a virtual environment with Python 3.11:

```console
$ uv venv --python 3.11
```

Note this requires the requested Python version to be available on the system. However, if
unavailable, uv will download Python for you. See the
[Python version](../concepts/python-versions.md) documentation for more details.

## Using a virtual environment

When using the default virtual environment name, uv will automatically find and use the virtual
environment during subsequent invocations.

```console
$ uv venv

$ # Install a package in the new virtual environment
$ uv pip install ruff
```

The virtual environment can be "activated" to make its packages available:

=== "macOS and Linux"

    ```console
    $ source .venv/bin/activate
    ```

=== "Windows"

    ```pwsh-session
    PS> .venv\Scripts\activate
    ```

!!! note

    The default activation script on Unix is for POSIX compliant shells like `sh`, `bash`, or `zsh`.
    There are additional activation scripts for common alternative shells.

    === "fish"

        ```console
        $ source .venv/bin/activate.fish
        ```

    === "csh / tcsh"


        ```console
        $ source .venv/bin/activate.csh
        ```

    === "Nushell"

        ```console
        $ use .venv\Scripts\activate.nu
        ```

## Deactivating an environment

To exit a virtual environment, use the `deactivate` command:

```console
$ deactivate
```

## Using arbitrary Python environments

Since uv has no dependency on Python, it can install into virtual environments other than its own.
For example, setting `VIRTUAL_ENV=/path/to/venv` will cause uv to install into `/path/to/venv`,
regardless of where uv is installed. Note that if `VIRTUAL_ENV` is set to a directory that is
**not** a [PEP 405 compliant](https://peps.python.org/pep-0405/#specification) virtual environment,
it will be ignored.

uv can also install into arbitrary, even non-virtual environments, with the `--python` argument
provided to `uv pip sync` or `uv pip install`. For example,
`uv pip install --python /path/to/python` will install into the environment linked to the
`/path/to/python` interpreter.

For convenience, `uv pip install --system` will install into the system Python environment. Using
`--system` is roughly equivalent to `uv pip install --python $(which python)`, but note that
executables that are linked to virtual environments will be skipped. Although we generally recommend
using virtual environments for dependency management, `--system` is appropriate in continuous
integration and containerized environments.

The `--system` flag is also used to opt in to mutating system environments. For example, the
`--python` argument can be used to request a Python version (e.g., `--python 3.12`), and uv will
search for an interpreter that meets the request. If uv finds a system interpreter (e.g.,
`/usr/lib/python3.12`), then the `--system` flag is required to allow modification of this
non-virtual Python environment. Without the `--system` flag, uv will ignore any interpreters that
are not in virtual environments. Conversely, when the `--system` flag is provided, uv will ignore
any interpreters that _are_ in virtual environments.

Installing into system Python across platforms and distributions is notoriously difficult. uv
supports the common cases, but will not work in all cases. For example, installing into system
Python on Debian prior to Python 3.10 is unsupported due to the
[distribution's patching of `distutils` (but not `sysconfig`)](https://ffy00.github.io/blog/02-python-debian-and-the-install-locations/).
While we always recommend the use of virtual environments, uv considers them to be required in these
non-standard environments.

If uv is installed in a Python environment, e.g., with `pip`, it can still be used to modify other
environments. However, when invoked with `python -m uv`, uv will default to using the parent
interpreter's environment. Invoking uv via Python adds startup overhead and is not recommended for
general usage.

uv itself does not depend on Python, but it does need to locate a Python environment to (1) install
dependencies into the environment and (2) build source distributions.

## Discovery of Python environments

When running a command that mutates an environment such as `uv pip sync` or `uv pip install`, uv
will search for a virtual environment in the following order:

- An activated virtual environment based on the `VIRTUAL_ENV` environment variable.
- An activated Conda environment based on the `CONDA_PREFIX` environment variable.
- A virtual environment at `.venv` in the current directory, or in the nearest parent directory.

If no virtual environment is found, uv will prompt the user to create one in the current directory
via `uv venv`.

If the `--system` flag is included, uv will skip virtual environments search for an installed Python
version. Similarly, when running a command that does not mutate the environment such as
`uv pip compile`, uv does not _require_ a virtual environment — however, a Python interpreter is
still required. See the documentation on
[Python discovery](../concepts/python-versions.md#discovery-of-python-versions) for details on the
discovery of installed Python versions.

    # The pip interface

uv provides a drop-in replacement for common `pip`, `pip-tools`, and `virtualenv` commands. These
commands work directly with the virtual environment, in contrast to uv's primary interfaces where
the virtual environment is managed automatically. The `uv pip` interface exposes the speed and
functionality of uv to power users and projects that are not ready to transition away from `pip` and
`pip-tools`.

The following sections discuss the basics of using `uv pip`:

- [Creating and using environments](./environments.md)
- [Installing and managing packages](./packages.md)
- [Inspecting environments and packages](./inspection.md)
- [Declaring package dependencies](./dependencies.md)
- [Locking and syncing environments](./compile.md)

Please note these commands do not _exactly_ implement the interfaces and behavior of the tools they
are based on. The further you stray from common workflows, the more likely you are to encounter
differences. Consult the [pip-compatibility guide](./compatibility.md) for details.

!!! important

    uv does not rely on or invoke pip. The pip interface is named as such to highlight its dedicated
    purpose of providing low-level commands that match pip's interface and to separate it from the
    rest of uv's commands which operate at a higher level of abstraction.

    # Inspecting environments

## Listing installed packages

To list all the packages in the environment:

```console
$ uv pip list
```

To list the packages in a JSON format:

```console
$ uv pip list --format json
```

To list all the packages in the environment in a `requirements.txt` format:

```console
$ uv pip freeze
```

## Inspecting a package

To show information about an installed package, e.g., `numpy`:

```console
$ uv pip show numpy
```

Multiple packages can be inspected at once.

## Verifying an environment

It is possible to install packages with conflicting requirements into an environment if installed in
multiple steps.

To check for conflicts or missing dependencies in the environment:

```console
$ uv pip check
```

    # Managing packages

## Installing a package

To install a package into the virtual environment, e.g., Flask:

```console
$ uv pip install flask
```

To install a package with optional dependencies enabled, e.g., Flask with the "dotenv" extra:

```console
$ uv pip install "flask[dotenv]"
```

To install multiple packages, e.g., Flask and Ruff:

```console
$ uv pip install flask ruff
```

To install a package with a constraint, e.g., Ruff v0.2.0 or newer:

```console
$ uv pip install 'ruff>=0.2.0'
```

To install a package at a specific version, e.g., Ruff v0.3.0:

```console
$ uv pip install 'ruff==0.3.0'
```

To install a package from the disk:

```console
$ uv pip install "ruff @ ./projects/ruff"
```

To install a package from GitHub:

```console
$ uv pip install "git+https://github.com/astral-sh/ruff"
```

To install a package from GitHub at a specific reference:

```console
$ # Install a tag
$ uv pip install "git+https://github.com/astral-sh/ruff@v0.2.0"

$ # Install a commit
$ uv pip install "git+https://github.com/astral-sh/ruff@1fadefa67b26508cc59cf38e6130bde2243c929d"

$ # Install a branch
$ uv pip install "git+https://github.com/astral-sh/ruff@main"
```

See the [Git authentication](../concepts/authentication/git.md) documentation for installation from
a private repository.

## Editable packages

Editable packages do not need to be reinstalled for changes to their source code to be active.

To install the current project as an editable package

```console
$ uv pip install -e .
```

To install a project in another directory as an editable package:

```console
$ uv pip install -e "ruff @ ./project/ruff"
```

## Installing packages from files

Multiple packages can be installed at once from standard file formats.

Install from a `requirements.txt` file:

```console
$ uv pip install -r requirements.txt
```

See the [`uv pip compile`](./compile.md) documentation for more information on `requirements.txt`
files.

Install from a `pyproject.toml` file:

```console
$ uv pip install -r pyproject.toml
```

Install from a `pyproject.toml` file with optional dependencies enabled, e.g., the "foo" extra:

```console
$ uv pip install -r pyproject.toml --extra foo
```

Install from a `pyproject.toml` file with all optional dependencies enabled:

```console
$ uv pip install -r pyproject.toml --all-extras
```

To install dependency groups in the current project directory's `pyproject.toml`, for example the
group `foo`:

```console
$ uv pip install --group foo
```

To specify the project directory where groups should be sourced from:

```console
$ uv pip install --project some/path/ --group foo --group bar
```

Alternatively, you can specify a path to a `pyproject.toml` for each group:

```console
$ uv pip install --group some/path/pyproject.toml:foo --group other/pyproject.toml:bar
```

!!! note

    As in pip, `--group` flags do not apply to other sources specified with flags like `-r` or `-e`.
    For instance, `uv pip install -r some/path/pyproject.toml --group foo` sources `foo`
    from `./pyproject.toml` and **not** `some/path/pyproject.toml`.

## Uninstalling a package

To uninstall a package, e.g., Flask:

```console
$ uv pip uninstall flask
```

To uninstall multiple packages, e.g., Flask and Ruff:

```console
$ uv pip uninstall flask ruff
```

    # Benchmarks

uv's performance is continually benchmarked against previous releases, and regularly compared to
other tools in the space, like pip and Poetry.

The latest benchmarks and details on the benchmarking process can be found in the
[GitHub repository](https://github.com/astral-sh/uv/blob/main/BENCHMARKS.md).

    # Environment variables

uv defines and respects the following environment variables:

### `UV_BREAK_SYSTEM_PACKAGES`

Equivalent to the `--break-system-packages` command-line argument. If set to `true`,
uv will allow the installation of packages that conflict with system-installed packages.

WARNING: `UV_BREAK_SYSTEM_PACKAGES=true` is intended for use in continuous integration
(CI) or containerized environments and should be used with caution, as modifying the system
Python can lead to unexpected behavior.

### `UV_BUILD_CONSTRAINT`

Equivalent to the `--build-constraint` command-line argument. If set, uv will use this file
as constraints for any source distribution builds. Uses space-separated list of files.

### `UV_CACHE_DIR`

Equivalent to the `--cache-dir` command-line argument. If set, uv will use this
directory for caching instead of the default cache directory.

### `UV_COMPILE_BYTECODE`

Equivalent to the `--compile-bytecode` command-line argument. If set, uv
will compile Python source files to bytecode after installation.

### `UV_COMPILE_BYTECODE_TIMEOUT`

Timeout (in seconds) for bytecode compilation.

### `UV_CONCURRENT_BUILDS`

Sets the maximum number of source distributions that uv will build
concurrently at any given time.

### `UV_CONCURRENT_DOWNLOADS`

Sets the maximum number of in-flight concurrent downloads that uv will
perform at any given time.

### `UV_CONCURRENT_INSTALLS`

Controls the number of threads used when installing and unzipping
packages.

### `UV_CONFIG_FILE`

Equivalent to the `--config-file` command-line argument. Expects a path to a
local `uv.toml` file to use as the configuration file.

### `UV_CONSTRAINT`

Equivalent to the `--constraint` command-line argument. If set, uv will use this
file as the constraints file. Uses space-separated list of files.

### `UV_CREDENTIALS_DIR`

The directory for storage of credentials when using a plain text backend.

### `UV_CUSTOM_COMPILE_COMMAND`

Equivalent to the `--custom-compile-command` command-line argument.

Used to override uv in the output header of the `requirements.txt` files generated by
`uv pip compile`. Intended for use-cases in which `uv pip compile` is called from within a wrapper
script, to include the name of the wrapper script in the output file.

### `UV_DEFAULT_INDEX`

Equivalent to the `--default-index` command-line argument. If set, uv will use
this URL as the default index when searching for packages.

### `UV_DEV`

Equivalent to the `--dev` command-line argument. If set, uv will include
development dependencies.

### `UV_DOWNLOAD_URL`

The URL from which to download uv using the standalone installer. By default, installs from
uv's GitHub Releases. `INSTALLER_DOWNLOAD_URL` is also supported as an alias, for backwards
compatibility.

### `UV_ENV_FILE`

`.env` files from which to load environment variables when executing `uv run` commands.

### `UV_EXCLUDE_NEWER`

Equivalent to the `--exclude-newer` command-line argument. If set, uv will
exclude distributions published after the specified date.

### `UV_EXTRA_INDEX_URL`

Equivalent to the `--extra-index-url` command-line argument. If set, uv will
use this space-separated list of URLs as additional indexes when searching for packages.
(Deprecated: use `UV_INDEX` instead.)

### `UV_FIND_LINKS`

Equivalent to the `--find-links` command-line argument. If set, uv will use this
comma-separated list of additional locations to search for packages.

### `UV_FORK_STRATEGY`

Equivalent to the `--fork-strategy` argument. Controls version selection during universal
resolution.

### `UV_FROZEN`

Equivalent to the `--frozen` command-line argument. If set, uv will run without
updating the `uv.lock` file.

### `UV_GITHUB_TOKEN`

Equivalent to the `--token` argument for self update. A GitHub token for authentication.

### `UV_GIT_LFS`

Enables fetching files stored in Git LFS when installing a package from a Git repository.

### `UV_HTTP_RETRIES`

The number of retries for HTTP requests. (default: 3)

### `UV_HTTP_TIMEOUT`

Timeout (in seconds) for HTTP requests. (default: 30 s)

### `UV_INDEX`

Equivalent to the `--index` command-line argument. If set, uv will use this
space-separated list of URLs as additional indexes when searching for packages.

### `UV_INDEX_STRATEGY`

Equivalent to the `--index-strategy` command-line argument.

For example, if set to `unsafe-best-match`, uv will consider versions of a given package
available across all index URLs, rather than limiting its search to the first index URL
that contains the package.

### `UV_INDEX_URL`

Equivalent to the `--index-url` command-line argument. If set, uv will use this
URL as the default index when searching for packages.
(Deprecated: use `UV_DEFAULT_INDEX` instead.)

### `UV_INDEX_{name}_PASSWORD`

Provides the HTTP Basic authentication password for a named index.

The `name` parameter is the name of the index. For example, given an index named `foo`,
the environment variable key would be `UV_INDEX_FOO_PASSWORD`.

### `UV_INDEX_{name}_USERNAME`

Provides the HTTP Basic authentication username for a named index.

The `name` parameter is the name of the index. For example, given an index named `foo`,
the environment variable key would be `UV_INDEX_FOO_USERNAME`.

### `UV_INIT_BUILD_BACKEND`

Equivalent to the `--build-backend` argument for `uv init`. Determines the default backend
to use when creating a new project.

### `UV_INSECURE_HOST`

Equivalent to the `--allow-insecure-host` argument.

### `UV_INSECURE_NO_ZIP_VALIDATION`

Disable ZIP validation for streamed wheels and ZIP-based source distributions.

WARNING: Disabling ZIP validation can expose your system to security risks by bypassing
integrity checks and allowing uv to install potentially malicious ZIP files. If uv rejects
a ZIP file due to failing validation, it is likely that the file is malformed; consider
filing an issue with the package maintainer.

### `UV_INSTALLER_GHE_BASE_URL`

The URL from which to download uv using the standalone installer and `self update` feature,
in lieu of the default GitHub Enterprise URL.

### `UV_INSTALLER_GITHUB_BASE_URL`

The URL from which to download uv using the standalone installer and `self update` feature,
in lieu of the default GitHub URL.

### `UV_INSTALL_DIR`

The directory in which to install uv using the standalone installer and `self update` feature.
Defaults to `~/.local/bin`.

### `UV_ISOLATED`

Equivalent to the `--isolated` command-line argument. If set, uv will avoid discovering
a `pyproject.toml` or `uv.toml` file.

### `UV_KEYRING_PROVIDER`

Equivalent to the `--keyring-provider` command-line argument. If set, uv
will use this value as the keyring provider.

### `UV_LIBC`

Overrides the environment-determined libc on linux systems when filling in the current platform
within Python version requests. Options are: `gnu`, `gnueabi`, `gnueabihf`, `musl`, and `none`.

### `UV_LINK_MODE`

Equivalent to the `--link-mode` command-line argument. If set, uv will use this as
a link mode.

### `UV_LOCKED`

Equivalent to the `--locked` command-line argument. If set, uv will assert that the
`uv.lock` remains unchanged.

### `UV_LOG_CONTEXT`

Add additional context and structure to log messages.

If logging is not enabled, e.g., with `RUST_LOG` or `-v`, this has no effect.

### `UV_MANAGED_PYTHON`

Require use of uv-managed Python versions.

### `UV_NATIVE_TLS`

Equivalent to the `--native-tls` command-line argument. If set to `true`, uv will
use the system's trust store instead of the bundled `webpki-roots` crate.

### `UV_NO_BINARY`

Equivalent to the `--no-binary` command-line argument. If set, uv will install
all packages from source. The resolver will still use pre-built wheels to
extract package metadata, if available.

### `UV_NO_BINARY_PACKAGE`

Equivalent to the `--no-binary-package` command line argument. If set, uv will
not use pre-built wheels for the given space-delimited list of packages.

### `UV_NO_BUILD`

Equivalent to the `--no-build` command-line argument. If set, uv will not build
source distributions.

### `UV_NO_BUILD_ISOLATION`

Equivalent to the `--no-build-isolation` command-line argument. If set, uv will
skip isolation when building source distributions.

### `UV_NO_BUILD_PACKAGE`

Equivalent to the `--no-build-package` command line argument. If set, uv will
not build source distributions for the given space-delimited list of packages.

### `UV_NO_CACHE`

Equivalent to the `--no-cache` command-line argument. If set, uv will not use the
cache for any operations.

### `UV_NO_CONFIG`

Equivalent to the `--no-config` command-line argument. If set, uv will not read
any configuration files from the current directory, parent directories, or user configuration
directories.

### `UV_NO_DEV`

Equivalent to the `--no-dev` command-line argument. If set, uv will exclude
development dependencies.

### `UV_NO_EDITABLE`

Equivalent to the `--no-editable` command-line argument. If set, uv
installs or exports any editable dependencies, including the project and any workspace
members, as non-editable.

### `UV_NO_ENV_FILE`

Ignore `.env` files when executing `uv run` commands.

### `UV_NO_GITHUB_FAST_PATH`

Disable GitHub-specific requests that allow uv to skip `git fetch` in some circumstances.

### `UV_NO_HF_TOKEN`

Disable Hugging Face authentication, even if `HF_TOKEN` is set.

### `UV_NO_INSTALLER_METADATA`

Skip writing `uv` installer metadata files (e.g., `INSTALLER`, `REQUESTED`, and `direct_url.json`) to site-packages `.dist-info` directories.

### `UV_NO_MANAGED_PYTHON`

Disable use of uv-managed Python versions.

### `UV_NO_MODIFY_PATH`

Avoid modifying the `PATH` environment variable when installing uv using the standalone
installer and `self update` feature. `INSTALLER_NO_MODIFY_PATH` is also supported as an
alias, for backwards compatibility.

### `UV_NO_PROGRESS`

Equivalent to the `--no-progress` command-line argument. Disables all progress output. For
example, spinners and progress bars.

### `UV_NO_SYNC`

Equivalent to the `--no-sync` command-line argument. If set, uv will skip updating
the environment.

### `UV_NO_VERIFY_HASHES`

Equivalent to the `--no-verify-hashes` argument. Disables hash verification for
`requirements.txt` files.

### `UV_NO_WRAP`

Use to disable line wrapping for diagnostics.

### `UV_OFFLINE`

Equivalent to the `--offline` command-line argument. If set, uv will disable network access.

### `UV_OVERRIDE`

Equivalent to the `--override` command-line argument. If set, uv will use this file
as the overrides file. Uses space-separated list of files.

### `UV_PRERELEASE`

Equivalent to the `--prerelease` command-line argument. For example, if set to
`allow`, uv will allow pre-release versions for all dependencies.

### `UV_PREVIEW`

Equivalent to the `--preview` argument. Enables preview mode.

### `UV_PREVIEW_FEATURES`

Equivalent to the `--preview-features` argument. Enables specific preview features.

### `UV_PROJECT`

Equivalent to the `--project` command-line argument.

### `UV_PROJECT_ENVIRONMENT`

Specifies the path to the directory to use for a project virtual environment.

See the [project documentation](../concepts/projects/config.md#project-environment-path)
for more details.

### `UV_PUBLISH_CHECK_URL`

Don't upload a file if it already exists on the index. The value is the URL of the index.

### `UV_PUBLISH_INDEX`

Equivalent to the `--index` command-line argument in `uv publish`. If
set, uv the index with this name in the configuration for publishing.

### `UV_PUBLISH_PASSWORD`

Equivalent to the `--password` command-line argument in `uv publish`. If
set, uv will use this password for publishing.

### `UV_PUBLISH_TOKEN`

Equivalent to the `--token` command-line argument in `uv publish`. If set, uv
will use this token (with the username `__token__`) for publishing.

### `UV_PUBLISH_URL`

Equivalent to the `--publish-url` command-line argument. The URL of the upload
endpoint of the index to use with `uv publish`.

### `UV_PUBLISH_USERNAME`

Equivalent to the `--username` command-line argument in `uv publish`. If
set, uv will use this username for publishing.

### `UV_PYPY_INSTALL_MIRROR`

Managed PyPy installations are downloaded from [python.org](https://downloads.python.org/).

This variable can be set to a mirror URL to use a
different source for PyPy installations. The provided URL will replace
`https://downloads.python.org/pypy` in, e.g.,
`https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`.
Distributions can be read from a local directory by using the `file://` URL scheme.

### `UV_PYTHON`

Equivalent to the `--python` command-line argument. If set to a path, uv will use
this Python interpreter for all operations.

### `UV_PYTHON_BIN_DIR`

Specifies the directory to place links to installed, managed Python executables.

### `UV_PYTHON_CACHE_DIR`

Specifies the directory for caching the archives of managed Python installations before
installation.

### `UV_PYTHON_CPYTHON_BUILD`

Pin managed CPython versions to a specific build version.

For CPython, this should be the build date (e.g., "20250814").

### `UV_PYTHON_DOWNLOADS`

Equivalent to the
[`python-downloads`](../reference/settings.md#python-downloads) setting and, when disabled, the
`--no-python-downloads` option. Whether uv should allow Python downloads.

### `UV_PYTHON_DOWNLOADS_JSON_URL`

Managed Python installations information is hardcoded in the `uv` binary.

This variable can be set to a URL pointing to JSON to use as a list for Python installations.
This will allow for setting each property of the Python installation, mostly the url part for offline mirror.

Note that currently, only local paths are supported.

### `UV_PYTHON_GRAALPY_BUILD`

Pin managed GraalPy versions to a specific build version.

For GraalPy, this should be the GraalPy version (e.g., "24.2.2").

### `UV_PYTHON_INSTALL_BIN`

Whether to install the Python executable into the `UV_PYTHON_BIN_DIR` directory.

### `UV_PYTHON_INSTALL_DIR`

Specifies the directory for storing managed Python installations.

### `UV_PYTHON_INSTALL_MIRROR`

Managed Python installations are downloaded from the Astral
[`python-build-standalone`](https://github.com/astral-sh/python-build-standalone) project.

This variable can be set to a mirror URL to use a different source for Python installations.
The provided URL will replace `https://github.com/astral-sh/python-build-standalone/releases/download` in, e.g.,
`https://github.com/astral-sh/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`.
Distributions can be read from a local directory by using the `file://` URL scheme.

### `UV_PYTHON_INSTALL_REGISTRY`

Whether to install the Python executable into the Windows registry.

### `UV_PYTHON_PREFERENCE`

Whether uv should prefer system or managed Python versions.

### `UV_PYTHON_PYODIDE_BUILD`

Pin managed Pyodide versions to a specific build version.

For Pyodide, this should be the Pyodide version (e.g., "0.28.1").

### `UV_PYTHON_PYPY_BUILD`

Pin managed PyPy versions to a specific build version.

For PyPy, this should be the PyPy version (e.g., "7.3.20").

### `UV_REQUEST_TIMEOUT`

Timeout (in seconds) for HTTP requests. Equivalent to `UV_HTTP_TIMEOUT`.

### `UV_REQUIRE_HASHES`

Equivalent to the `--require-hashes` command-line argument. If set to `true`,
uv will require that all dependencies have a hash specified in the requirements file.

### `UV_RESOLUTION`

Equivalent to the `--resolution` command-line argument. For example, if set to
`lowest-direct`, uv will install the lowest compatible versions of all direct dependencies.

### `UV_S3_ENDPOINT_URL`

The URL to treat as an S3-compatible storage endpoint. Requests to this endpoint
will be signed using AWS Signature Version 4 based on the `AWS_ACCESS_KEY_ID`,
`AWS_SECRET_ACCESS_KEY`, `AWS_PROFILE`, and `AWS_CONFIG_FILE` environment variables.

### `UV_STACK_SIZE`

Use to set the stack size used by uv.

The value is in bytes, and if both `UV_STACK_SIZE` are `RUST_MIN_STACK` unset, uv uses a 4MB
(4194304) stack. `UV_STACK_SIZE` takes precedence over `RUST_MIN_STACK`.

Unlike the normal `RUST_MIN_STACK` semantics, this can affect main thread
stack size, because we actually spawn our own main2 thread to work around
the fact that Windows' real main thread is only 1MB. That thread has size
`max(UV_STACK_SIZE, 1MB)`.

### `UV_SYSTEM_PYTHON`

Equivalent to the `--system` command-line argument. If set to `true`, uv will
use the first Python interpreter found in the system `PATH`.

WARNING: `UV_SYSTEM_PYTHON=true` is intended for use in continuous integration (CI)
or containerized environments and should be used with caution, as modifying the system
Python can lead to unexpected behavior.

### `UV_TEST_NO_HTTP_RETRY_DELAY`

Used to disable delay for HTTP retries in tests.

### `UV_TOOL_BIN_DIR`

Specifies the "bin" directory for installing tool executables.

### `UV_TOOL_DIR`

Specifies the directory where uv stores managed tools.

### `UV_TORCH_BACKEND`

Equivalent to the `--torch-backend` command-line argument (e.g., `cpu`, `cu126`, or `auto`).

### `UV_UNMANAGED_INSTALL`

Used ephemeral environments like CI to install uv to a specific path while preventing
the installer from modifying shell profiles or environment variables.

### `UV_VENV_CLEAR`

Equivalent to the `--clear` command-line argument. If set, uv will remove any
existing files or directories at the target path.

### `UV_VENV_SEED`

Install seed packages (one or more of: `pip`, `setuptools`, and `wheel`) into the virtual environment
created by `uv venv`.

Note that `setuptools` and `wheel` are not included in Python 3.12+ environments.



## Externally defined variables

uv also reads the following externally defined environment variables:

### `ALL_PROXY`

General proxy for all network requests.

### `ANDROID_API_LEVEL`

Used with `--python-platform aarch64-linux-android` and related variants to set the
Android API level. (i.e., the minimum supported Android API level).

Defaults to `24`.

### `APPDATA`

Path to user-level configuration directory on Windows systems.

### `AWS_ACCESS_KEY_ID`

The AWS access key ID to use when signing S3 requests.

### `AWS_CONFIG_FILE`

The AWS config file to use when signing S3 requests.

### `AWS_DEFAULT_REGION`

The default AWS region to use when signing S3 requests, if `AWS_REGION` is not set.

### `AWS_PROFILE`

The AWS profile to use when signing S3 requests.

### `AWS_REGION`

The AWS region to use when signing S3 requests.

### `AWS_SECRET_ACCESS_KEY`

The AWS secret access key to use when signing S3 requests.

### `AWS_SESSION_TOKEN`

The AWS session token to use when signing S3 requests.

### `AWS_SHARED_CREDENTIALS_FILE`

The AWS shared credentials file to use when signing S3 requests.

### `BASH_VERSION`

Used to detect Bash shell usage.

### `CLICOLOR_FORCE`

Use to control color via `anstyle`.

### `COLUMNS`

Overrides terminal width used for wrapping. This variable is not read by uv directly.

This is a quasi-standard variable, described, e.g., in `ncurses(3x)`.

### `CONDA_DEFAULT_ENV`

Used to determine the name of the active Conda environment.

### `CONDA_PREFIX`

Used to detect the path of an active Conda environment.

### `CONDA_ROOT`

Used to determine the root install path of Conda.

### `FISH_VERSION`

Used to detect Fish shell usage.

### `FORCE_COLOR`

Forces colored output regardless of terminal support.

See [force-color.org](https://force-color.org).

### `GITHUB_ACTIONS`

Indicates that the current process is running in GitHub Actions.

`uv publish` may attempt trusted publishing flows when set
to `true`.

### `GITLAB_CI`

Indicates that the current process is running in GitLab CI.

`uv publish` may attempt trusted publishing flows when set
to `true`.

### `HF_TOKEN`

Authentication token for Hugging Face requests. When set, uv will use this token
when making requests to `https://huggingface.co/` and any subdomains.

### `HOME`

The standard `HOME` env var.

### `HTTPS_PROXY`

Proxy for HTTPS requests.

### `HTTP_PROXY`

Proxy for HTTP requests.

### `HTTP_TIMEOUT`

Timeout (in seconds) for HTTP requests. Equivalent to `UV_HTTP_TIMEOUT`.

### `IPHONEOS_DEPLOYMENT_TARGET`

Used with `--python-platform arm64-apple-ios` and related variants to set the
deployment target (i.e., the minimum supported iOS version).

Defaults to `13.0`.

### `JPY_SESSION_NAME`

Used to detect when running inside a Jupyter notebook.

### `KSH_VERSION`

Used to detect Ksh shell usage.

### `LOCALAPPDATA`

Used to look for Microsoft Store Pythons installations.

### `MACOSX_DEPLOYMENT_TARGET`

Used with `--python-platform macos` and related variants to set the
deployment target (i.e., the minimum supported macOS version).

Defaults to `13.0`, the least-recent non-EOL macOS version at time of writing.

### `NETRC`

Use to set the .netrc file location.

### `NO_COLOR`

Disables colored output (takes precedence over `FORCE_COLOR`).

See [no-color.org](https://no-color.org).

### `NO_PROXY`

Comma-separated list of hostnames (e.g., `example.com`) and/or patterns (e.g., `192.168.1.0/24`) that should bypass the proxy.

### `NU_VERSION`

Used to detect `NuShell` usage.

### `PAGER`

The standard `PAGER` posix env var. Used by `uv` to configure the appropriate pager.

### `PATH`

The standard `PATH` env var.

### `PROMPT`

Used to detect the use of the Windows Command Prompt (as opposed to PowerShell).

### `PWD`

The standard `PWD` posix env var.

### `PYC_INVALIDATION_MODE`

The validation modes to use when run with `--compile`.

See [`PycInvalidationMode`](https://docs.python.org/3/library/py_compile.html#py_compile.PycInvalidationMode).

### `PYTHONPATH`

Adds directories to Python module search path (e.g., `PYTHONPATH=/path/to/modules`).

### `PYX_API_KEY`

The pyx API key (e.g., `sk-pyx-...`).

### `PYX_API_URL`

The URL of the pyx Simple API server.

### `PYX_AUTH_TOKEN`

The pyx authentication token (e.g., `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...`), as output by `uv auth token`.

### `PYX_CDN_DOMAIN`

The domain of the pyx CDN.

### `PYX_CREDENTIALS_DIR`

Specifies the directory where uv stores pyx credentials.

### `RUST_BACKTRACE`

If set, it can be used to display more stack trace details when a panic occurs.
This is used by uv particularly on windows to show more details during a platform exception.

For example:

* `RUST_BACKTRACE=1` will print a short backtrace.
* `RUST_BACKTRACE=full` will print a full backtrace.

See the [Rust backtrace documentation](https://doc.rust-lang.org/std/backtrace/index.html)
for more.

### `RUST_LOG`

If set, uv will use this value as the log level for its `--verbose` output. Accepts
any filter compatible with the `tracing_subscriber` crate.

For example:

* `RUST_LOG=uv=debug` is the equivalent of adding `--verbose` to the command line
* `RUST_LOG=trace` will enable trace-level logging.

See the [tracing documentation](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax)
for more.

### `RUST_MIN_STACK`

Use to set the stack size used by uv.

The value is in bytes, and if both `UV_STACK_SIZE` are `RUST_MIN_STACK` unset, uv uses a 4MB
(4194304) stack. `UV_STACK_SIZE` takes precedence over `RUST_MIN_STACK`.

Prefer setting `UV_STACK_SIZE`, since `RUST_MIN_STACK` also affects subprocesses, such as
build backends that use Rust code.

Unlike the normal `RUST_MIN_STACK` semantics, this can affect main thread
stack size, because we actually spawn our own main2 thread to work around
the fact that Windows' real main thread is only 1MB. That thread has size
`max(RUST_MIN_STACK, 1MB)`.

### `SHELL`

The standard `SHELL` posix env var.

### `SSL_CERT_FILE`

Custom certificate bundle file path for SSL connections.

### `SSL_CLIENT_CERT`

If set, uv will use this file for mTLS authentication.
This should be a single file containing both the certificate and the private key in PEM format.

### `SYSTEMDRIVE`

Path to system-level configuration directory on Windows systems.

### `TRACING_DURATIONS_FILE`

Use to create the tracing durations file via the `tracing-durations-export` feature.

### `USERPROFILE`

Path to root directory of user's profile on Windows systems.

### `UV`

The path to the binary that was used to invoke uv.

This is propagated to all subprocesses spawned by uv.

If the executable was invoked through a symbolic link, some platforms will return the path
of the symbolic link and other platforms will return the path of the symbolic link’s target.

See <https://doc.rust-lang.org/std/env/fn.current_exe.html#security> for security
considerations.

### `VIRTUAL_ENV`

Used to detect an activated virtual environment.

### `VIRTUAL_ENV_DISABLE_PROMPT`

If set to `1` before a virtual environment is activated, then the
virtual environment name will not be prepended to the terminal prompt.

### `XDG_BIN_HOME`

Path to directory where executables are installed.

### `XDG_CACHE_HOME`

Path to cache directory on Unix systems.

### `XDG_CONFIG_DIRS`

Path to system-level configuration directory on Unix systems.

### `XDG_CONFIG_HOME`

Path to user-level configuration directory on Unix systems.

### `XDG_DATA_HOME`

Path to directory for storing managed Python installations and tools.

### `ZDOTDIR`

Used to determine which `.zshenv` to use when Zsh is being used.

### `ZSH_VERSION`

Used to detect Zsh shell usage.


    # Reference

The reference section provides information about specific parts of uv:

- [Commands](./cli.md): A reference for uv's command line interface.
- [Settings](./settings.md): A reference for uv's configuration schema.
- [Resolver](./internals/resolver.md): Details about the internals of uv's resolver.
- [Policies](./policies/index.md): uv's versioning policy, platform support policy, and license.

Looking for a broader overview? Check out the [concepts](../concepts/index.md) documentation.

    # The uv installer

## Changing the installation path

By default, uv is installed to `~/.local/bin`. If `XDG_BIN_HOME` is set, it will be used instead.
Similarly, if `XDG_DATA_HOME` is set, the target directory will be inferred as
`XDG_DATA_HOME/../bin`.

To change the installation path, use `UV_INSTALL_DIR`:

=== "macOS and Linux"

    ```console
    $ curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="/custom/path" sh
    ```

=== "Windows"

    ```pwsh-session
    PS> powershell -ExecutionPolicy ByPass -c {$env:UV_INSTALL_DIR = "C:\Custom\Path";irm https://astral.sh/uv/install.ps1 | iex}
    ```

## Disabling shell modifications

The installer may also update your shell profiles to ensure the uv binary is on your `PATH`. To
disable this behavior, use `UV_NO_MODIFY_PATH`. For example:

```console
$ curl -LsSf https://astral.sh/uv/install.sh | env UV_NO_MODIFY_PATH=1 sh
```

If installed with `UV_NO_MODIFY_PATH`, subsequent operations, like `uv self update`, will not modify
your shell profiles.

## Unmanaged installations

In ephemeral environments like CI, use `UV_UNMANAGED_INSTALL` to install uv to a specific path while
preventing the installer from modifying shell profiles or environment variables:

```console
$ curl -LsSf https://astral.sh/uv/install.sh | env UV_UNMANAGED_INSTALL="/custom/path" sh
```

The use of `UV_UNMANAGED_INSTALL` will also disable self-updates (via `uv self update`).

## Passing options to the installation script

Using environment variables is recommended because they are consistent across platforms. However,
options can be passed directly to the installation script. For example, to see the available
options:

```console
$ curl -LsSf https://astral.sh/uv/install.sh | sh -s -- --help
```

    # Internals

The internals section provides details about uv's internal components and implementation details.

- [Resolver](./resolver.md)

    # Resolver internals

!!! tip

    This document focuses on the internal workings of uv's resolver. For using uv, see the
    [resolution concept](../../concepts/resolution.md) documentation.

## Resolver

As defined in a textbook, resolution, or finding a set of version to install from a given set of
requirements, is equivalent to the
[SAT problem](https://en.wikipedia.org/wiki/Boolean_satisfiability_problem) and thereby NP-complete:
in the worst case you have to try all possible combinations of all versions of all packages and
there are no general, fast algorithms. In practice, this is misleading for a number of reasons:

- The slowest part of resolution in uv is loading package and version metadata, even if it's cached.
- There are many possible solutions, but some are preferable to others. For example, we generally
  prefer using the latest version of packages.
- Package dependencies are complex, e.g., there are contiguous versions ranges — not arbitrary
  boolean inclusion/exclusions of versions, adjacent releases often have the same or similar
  requirements, etc.
- For most resolutions, the resolver doesn't need to backtrack, picking versions iteratively is
  sufficient. If there are version preferences from a previous resolution, barely any work needs to
  be done.
- When resolution fails, more information is needed than a message that there is no solution (as is
  seen in SAT solvers). Instead, the resolver should produce an understandable error trace that
  states which packages are involved in away to allows a user to remove the conflict.
- The most important heuristic for performance and user experience is determining the order in which
  decisions are made through prioritization.

uv uses [pubgrub-rs](https://github.com/pubgrub-rs/pubgrub), the Rust implementation of
[PubGrub](https://nex3.medium.com/pubgrub-2fb6470504f), an incremental version solver. PubGrub in uv
works in the following steps:

- Start with a partial solution that declares which packages versions have been selected and which
  are undecided. Initially, only a virtual root package is decided.
- The highest priority package is selected from the undecided packages. Roughly, packages with URLs
  (including file, git, etc.) have the highest priority, then those with more exact specifiers (such
  as `==`), then those with less strict specifiers. Inside each category, packages are ordered by
  when they were first seen (i.e. order in a file), making the resolution deterministic.
- A version is picked for the selected package. The version must works with all specifiers from the
  requirements in the partial solution and must not be previously marked as incompatible. The
  resolver prefers versions from a lockfile (`uv.lock` or `-o requirements.txt`) and those installed
  in the current environment. Versions are checked from highest to lowest (unless using an
  alternative [resolution strategy](../../concepts/resolution.md#resolution-strategy)).
- All requirements of the selected package version are added to the undecided packages. uv
  prefetches their metadata in the background to improve performance.
- The process is either repeated with the next package unless a conflict is detected, in which the
  resolver will backtrack. For example, the partial solution contains, among other packages, `a 2`
  then `b 2` with the requirements `a 2 -> c 1` and `b 2 -> c 2`. No compatible version of `c` can
  be found. PubGrub can determine this was caused by `a 2` and `b 2` and add the incompatibility
  `{a 2, b 2}`, meaning that when either is picked, the other cannot be selected. The partial
  solution is restored to `a 2` with the tracked incompatibility and the resolver attempts to pick a
  new version for `b`.

Eventually, the resolver either picks compatible versions for all packages (a successful resolution)
or there is an incompatibility including the virtual "root" package which defines the versions
requested by the user. An incompatibility with the root package indicates that whatever versions of
the root dependencies and their transitive dependencies are picked, there will always be a conflict.
From the incompatibilities tracked in PubGrub, an error message is constructed to enumerate the
involved packages.

!!! tip

    For more details on the PubGrub algorithm, see [Internals of the PubGrub
    algorithm](https://pubgrub-rs-guide.pages.dev/internals/intro).

In addition to PubGrub's base algorithm, we also use a heuristic that backtracks and switches the
order of two packages if they have been conflicting too much.

## Forking

Python resolvers historically didn't support backtracking, and even with backtracking, resolution
was usually limited to single environment, which one specific architecture, operating system, Python
version, and Python implementation. Some packages use contradictory requirements for different
environments, for example:

```
numpy>=2,<3 ; python_version >= "3.11"
numpy>=1.16,<2 ; python_version < "3.11"
```

Since Python only allows one version of each package, a naive resolver would error here. Inspired by
[Poetry](https://github.com/python-poetry/poetry), uv uses a forking resolver: whenever there are
multiple requirements for a package with different markers, the resolution is split.

In the above example, the partial solution would be split into two resolutions, one for
`python_version >= "3.11"` and one for `python_version < "3.11"`.

If markers overlap or are missing a part of the marker space, the resolver splits additional times —
there can be many forks per package. For example, given:

```
flask > 1 ; sys_platform == 'darwin'
flask > 2 ; sys_platform == 'win32'
flask
```

A fork would be created for `sys_platform == 'darwin'`, for `sys_platform == 'win32'`, and for
`sys_platform != 'darwin' and sys_platform != 'win32'`.

Forks can be nested, e.g., each fork is dependent on any previous forks that occurred. Forks with
identical packages are merged to keep the number of forks low.

!!! tip

    Forking can be observed in the logs of `uv lock -v` by looking for
    `Splitting resolution on ...`, `Solving split ... (requires-python: ...)` and `Split ... resolution
    took ...`.

One difficulty in a forking resolver is that where splits occur is dependent on the order packages
are seen, which is in turn dependent on the preferences, e.g., from `uv.lock`. So it is possible for
the resolver to solve the requirements with specific forks, write this to the lockfile, and when the
resolver is invoked again, a different solution is found because the preferences result in different
fork points. To avoid this, the `resolution-markers` of each fork and each package that diverges
between forks is written to the lockfile. When performing a new resolution, the forks from the
lockfile are used to ensure the resolution is stable. When requirements change, new forks may be
added to the saved forks.

## Wheel tags

While uv's resolution is universal with respect to environment markers, this doesn't extend to wheel
tags. Wheel tags can encode the Python version, Python implementation, operating system, and
architecture. For example, `torch-2.4.0-cp312-cp312-manylinux2014_aarch64.whl` is only compatible
with CPython 3.12 on arm64 Linux with `glibc>=2.17` (per the `manylinux2014` policy), while
`tqdm-4.66.4-py3-none-any.whl` works with all Python 3 versions and interpreters on any operating
system and architecture. Most projects have a universally compatible source distribution that can be
used when attempted to install a package that has no compatible wheel, but some packages, such as
`torch`, don't publish a source distribution. In this case an installation on, e.g., Python 3.13, an
uncommon operating system, or architecture, will fail and complain that there is no matching wheel.

## Marker and wheel tag filtering

In every fork, we know what markers are possible. In non-universal resolution, we know their exact
values. In universal mode, we know at least a constraint for the python requirement, e.g.,
`requires-python = ">=3.12"` means that `importlib_metadata; python_version < "3.10"` can be
discarded because it can never be installed. If additionally `tool.uv.environments` is set, we can
filter out requirements with markers disjoint with those environments. Inside each fork, we can
additionally filter by the fork markers.

There is some redundancy in the marker expressions, where the value of one marker field implies the
value of another field. Internally, we normalize `python_version` and `python_full_version` as well
as known values of `platform_system` and `sys_platform` to a shared canonical representation, so
they can match against each other.

When we selected a version with a local tag (e.g.,`1.2.3+localtag`) and the wheels don't cover
support for Windows, Linux and macOS, and there is a base version without tag (e.g.,`1.2.3`) with
support for a missing platform, we fork trying to extend the platform support by using both the
version with local tag and without local tag depending on the platform. This helps with packages
that use the local tag for different hardware accelerators such as torch. While there is no 1:1
mapping between wheel tags and markers, we can do a mapping for well-known platforms, including
Windows, Linux and macOS.

## Requires-python

To ensure that a resolution with `requires-python = ">=3.9"` can actually be installed for the
included Python versions, uv requires that all dependencies have the same minimum Python version.
Package versions that declare a higher minimum Python version, e.g., `requires-python = ">=3.10"`,
are rejected, because a resolution with that version can't be installed on Python 3.9. For
simplicity and forward compatibility, only lower bounds in `requires-python` are respected. For
example, if a package declares `requires-python = ">=3.8,<4"`, the `<4` marker is not propagated to
the entire resolution.

This default is a problem for packages that use the version-dependent C API of CPython, such as
numpy. Each numpy release support 4 Python minor versions, e.g., numpy 2.0.0 has wheels for CPython
3.9 through 3.12 and declares `requires-python = ">=3.9"`, while numpy 2.1.0 has wheels for CPython
3.10 through 3.13 and declares `requires-python = ">=3.10"`. The means that when we resolve a
`numpy>=2,<3` requirement in a project with `requires-python = ">=3.9"`, we resolve numpy 2.0.0 and
the lockfile doesn't install on Python 3.13 or newer. To alleviate this, whenever we reject a
version due to a too high Python requirement, we fork on that Python version. This behavior is
controlled by `--fork-strategy`. In the example case, upon encountering numpy 2.1.0 we fork into
Python versions `>=3.9,<3.10` and `>=3.10` and resolve two different numpy versions:

```
numpy==2.0.0; python_version >= "3.9" and python_version < "3.10"
numpy==2.1.0; python_version >= "3.10"
```

## Prioritization

Prioritization is important for both performance and for better resolutions.

If we try many versions we have to later discard, resolution is slow, both because we have to read
metadata we didn't need and because we have to track a lot of (conflict) information for this
discarded subtree.

There are expectations about which solution uv should choose, even if the version constraints allow
multiple solutions. Generally, a desirable solution prioritizes use the highest versions for direct
dependencies over those for indirect dependencies, it avoids backtracking to very old versions and
can be installed on a target machine.

Internally, uv represent each package with a given package name as a number of virtual packages, for
example, one package for each activated extra, for dependency groups, or for having a marker. While
PubGrub needs to choose a version for each virtual package, uv's prioritization works on the package
name level.

Whenever we encounter a requirement on a package, we match it to a priority. The root package and
URL requirements have the highest priority, then singleton requirements with the `==` operator, as
their version can be directly determined, then highly conflicting packages (next paragraph), and
finally all other packages. Inside each category, packages are sorted by when they were first
encountered, creating a breadth first search that prioritizes direct dependencies including
workspace dependencies over transitive dependencies.

A common problem is that we have a package A with a higher priority than package B, and B is only
compatible with older versions of A. We decide the latest version for package A. Each time we decide
a version for B, it is immediately discarded due to the conflict with A. We have to try all possible
versions of B, until we have either exhausted the possible range (slow), pick a very old version
that doesn't depend on A, but most likely isn't compatible with the project either (bad) or fail to
build a very old version (bad). Once we see such conflict happen five time, we set A and B to
special highly-conflicting priority levels, and set them so that B is decided before A. We then
manually backtrack to a state before deciding A, in the next iteration now deciding B instead of A.
See [#8157](https://github.com/astral-sh/uv/issues/8157) and
[#9843](https://github.com/astral-sh/uv/pull/9843) for a more detailed description with real world
examples.

    # Policies

- [Versioning](./versioning.md)
- [Platform support](./platforms.md)
- [License](./license.md)

    # License

uv is licensed under either of

- Apache License, Version 2.0

  [LICENSE-APACHE](https://github.com/astral-sh/uv/blob/main/LICENSE-APACHE) or
  <https://www.apache.org/licenses/LICENSE-2.0>

- MIT License

  [LICENSE-MIT](https://github.com/astral-sh/uv/blob/main/LICENSE-MIT) or
  <https://opensource.org/licenses/MIT>

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in uv
by you, as defined in the Apache-2.0 license, shall be dually licensed as above, without any
additional terms or conditions.

    # Platform support

uv has Tier 1 support for the following platforms:

- macOS (Apple Silicon)
- macOS (x86_64)
- Linux (x86_64)
- Windows (x86_64)

uv is continuously built, tested, and developed against its Tier 1 platforms. Inspired by the Rust
project, Tier 1 can be thought of as
["guaranteed to work"](https://doc.rust-lang.org/beta/rustc/platform-support.html).

uv has Tier 2 support
(["guaranteed to build"](https://doc.rust-lang.org/beta/rustc/platform-support.html)) for the
following platforms:

- Linux (PPC64)
- Linux (PPC64LE)
- Linux (aarch64)
- Linux (armv7)
- Linux (i686)
- Linux (s390x)

uv ships pre-built wheels to [PyPI](https://pypi.org/project/uv/) for its Tier 1 and Tier 2
platforms. However, while Tier 2 platforms are continuously built, they are not continuously tested
or developed against, and so stability may vary in practice.

Beyond the Tier 1 and Tier 2 platforms, uv is known to build on i686 Windows, and known _not_ to
build on aarch64 Windows, but does not consider either platform to be supported at this time. The
minimum supported Windows versions are Windows 10 and Windows Server 2016, following
[Rust's own Tier 1 support](https://blog.rust-lang.org/2024/02/26/Windows-7.html).

## macOS versions

uv supports macOS 13+ (Ventura).

uv is known to work on macOS 12, but requires installation of a `realpath` executable.

## Python support

uv supports and is tested against the following Python versions:

- 3.8
- 3.9
- 3.10
- 3.11
- 3.12
- 3.13
- 3.14

uv has Tier 1 support for the following Python implementations:

- CPython

As with platforms, Tier 1 support can be thought of "guaranteed to work". uv supports managed
installations of these implementations, and the builds are maintained by Astral.

uv has Tier 2 support for:

- PyPy
- GraalPy

uv is "expected to work" with these implementations. uv also supports managed installations of these
Python implementations, but the builds are not maintained by Astral.

uv has Tier 3 support for:

- Pyston
- Pyodide

uv "should work" with these implementations, but stability may vary.

    # Versioning

uv uses a custom versioning scheme in which the minor version number is bumped for breaking changes,
and the patch version number is bumped for bug fixes, enhancements, and other non-breaking changes.

uv is widely used in production. However, we value the ability to iterate on new features quickly
and gather changes that _could_ be breaking into clearly marked releases.

Once uv v1.0.0 is released, the versioning scheme will adhere to
[Semantic Versioning](https://semver.org/). There is not a particular goal that must be achieved for
uv to reach this milestone.

uv's changelog can be [viewed on GitHub](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md).

## Cache versioning

Cache versions are considered internal to uv, and so may be changed in a minor or patch release. See
[Cache versioning](../../concepts/cache.md#cache-versioning) for more.

## Lockfile versioning

The `uv.lock` schema version is considered part of the public API, and so will only be incremented
in a minor release as a breaking change. See
[Lockfile versioning](../../concepts/resolution.md#lockfile-versioning) for more.

## Minimum supported Rust version

The minimum supported Rust version required to compile uv is listed in the `rust-version` key of the
`[workspace.package]` section in `Cargo.toml`. It may change in any release (minor or patch). It
will never be newer than N-2 Rust versions, where N is the latest stable version. For example, if
the latest stable Rust version is 1.85, uv's minimum supported Rust version will be at most 1.83.

This is only relevant to users who build uv from source. Installing uv from the Python package index
usually installs a pre-built binary and does not require Rust compilation.

    ## Project metadata
### [`build-constraint-dependencies`](#build-constraint-dependencies) {: #build-constraint-dependencies }

Constraints to apply when solving build dependencies.

Build constraints are used to restrict the versions of build dependencies that are selected
when building a package during resolution or installation.

Including a package as a constraint will _not_ trigger installation of the package during
a build; instead, the package must be requested elsewhere in the project's build dependency
graph.

!!! note
    In `uv lock`, `uv sync`, and `uv run`, uv will only read `build-constraint-dependencies` from
    the `pyproject.toml` at the workspace root, and will ignore any declarations in other
    workspace members or `uv.toml` files.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv]
# Ensure that the setuptools v60.0.0 is used whenever a package has a build dependency
# on setuptools.
build-constraint-dependencies = ["setuptools==60.0.0"]
```

---

### [`conflicts`](#conflicts) {: #conflicts }

Declare collections of extras or dependency groups that are conflicting
(i.e., mutually exclusive).

It's useful to declare conflicts when two or more extras have mutually
incompatible dependencies. For example, extra `foo` might depend
on `numpy==2.0.0` while extra `bar` depends on `numpy==2.1.0`. While these
dependencies conflict, it may be the case that users are not expected to
activate both `foo` and `bar` at the same time, making it possible to
generate a universal resolution for the project despite the incompatibility.

By making such conflicts explicit, uv can generate a universal resolution
for a project, taking into account that certain combinations of extras and
groups are mutually exclusive. In exchange, installation will fail if a
user attempts to activate both conflicting extras.

**Default value**: `[]`

**Type**: `list[list[dict]]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv]
# Require that `package[extra1]` and `package[extra2]` are resolved
# in different forks so that they cannot conflict with one another.
conflicts = [
    [
        { extra = "extra1" },
        { extra = "extra2" },
    ]
]

# Require that the dependency groups `group1` and `group2`
# are resolved in different forks so that they cannot conflict
# with one another.
conflicts = [
    [
        { group = "group1" },
        { group = "group2" },
    ]
]
```

---

### [`constraint-dependencies`](#constraint-dependencies) {: #constraint-dependencies }

Constraints to apply when resolving the project's dependencies.

Constraints are used to restrict the versions of dependencies that are selected during
resolution.

Including a package as a constraint will _not_ trigger installation of the package on its
own; instead, the package must be requested elsewhere in the project's first-party or
transitive dependencies.

!!! note
    In `uv lock`, `uv sync`, and `uv run`, uv will only read `constraint-dependencies` from
    the `pyproject.toml` at the workspace root, and will ignore any declarations in other
    workspace members or `uv.toml` files.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv]
# Ensure that the grpcio version is always less than 1.65, if it's requested by a
# direct or transitive dependency.
constraint-dependencies = ["grpcio<1.65"]
```

---

### [`default-groups`](#default-groups) {: #default-groups }

The list of `dependency-groups` to install by default.

Can also be the literal `"all"` to default enable all groups.

**Default value**: `["dev"]`

**Type**: `str | list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv]
default-groups = ["docs"]
```

---

### [`dependency-groups`](#dependency-groups) {: #dependency-groups }

Additional settings for `dependency-groups`.

Currently this can only be used to add `requires-python` constraints
to dependency groups (typically to inform uv that your dev tooling
has a higher python requirement than your actual project).

This cannot be used to define dependency groups, use the top-level
`[dependency-groups]` table for that.

**Default value**: `[]`

**Type**: `dict`

**Example usage**:

```toml title="pyproject.toml"

[tool.uv.dependency-groups]
my-group = {requires-python = ">=3.12"}
```

---

### [`dev-dependencies`](#dev-dependencies) {: #dev-dependencies }

The project's development dependencies.

Development dependencies will be installed by default in `uv run` and `uv sync`, but will
not appear in the project's published metadata.

Use of this field is not recommend anymore. Instead, use the `dependency-groups.dev` field
which is a standardized way to declare development dependencies. The contents of
`tool.uv.dev-dependencies` and `dependency-groups.dev` are combined to determine the final
requirements of the `dev` dependency group.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv]
dev-dependencies = ["ruff==0.5.0"]
```

---

### [`environments`](#environments) {: #environments }

A list of supported environments against which to resolve dependencies.

By default, uv will resolve for all possible environments during a `uv lock` operation.
However, you can restrict the set of supported environments to improve performance and avoid
unsatisfiable branches in the solution space.

These environments will also be respected when `uv pip compile` is invoked with the
`--universal` flag.

**Default value**: `[]`

**Type**: `str | list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv]
# Resolve for macOS, but not for Linux or Windows.
environments = ["sys_platform == 'darwin'"]
```

---

### [`index`](#index) {: #index }

The indexes to use when resolving dependencies.

Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
(the simple repository API), or a local directory laid out in the same format.

Indexes are considered in the order in which they're defined, such that the first-defined
index has the highest priority. Further, the indexes provided by this setting are given
higher priority than any indexes specified via [`index_url`](#index-url) or
[`extra_index_url`](#extra-index-url). uv will only consider the first index that contains
a given package, unless an alternative [index strategy](#index-strategy) is specified.

If an index is marked as `explicit = true`, it will be used exclusively for the
dependencies that select it explicitly via `[tool.uv.sources]`, as in:

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

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

If an index is marked as `default = true`, it will be moved to the end of the prioritized list, such that it is
given the lowest priority when resolving packages. Additionally, marking an index as default will disable the
PyPI default index.

**Default value**: `[]`

**Type**: `dict`

**Example usage**:

```toml title="pyproject.toml"

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

---

### [`managed`](#managed) {: #managed }

Whether the project is managed by uv. If `false`, uv will ignore the project when
`uv run` is invoked.

**Default value**: `true`

**Type**: `bool`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv]
managed = false
```

---

### [`override-dependencies`](#override-dependencies) {: #override-dependencies }

Overrides to apply when resolving the project's dependencies.

Overrides are used to force selection of a specific version of a package, regardless of the
version requested by any other package, and regardless of whether choosing that version
would typically constitute an invalid resolution.

While constraints are _additive_, in that they're combined with the requirements of the
constituent packages, overrides are _absolute_, in that they completely replace the
requirements of any constituent packages.

Including a package as an override will _not_ trigger installation of the package on its
own; instead, the package must be requested elsewhere in the project's first-party or
transitive dependencies.

!!! note
    In `uv lock`, `uv sync`, and `uv run`, uv will only read `override-dependencies` from
    the `pyproject.toml` at the workspace root, and will ignore any declarations in other
    workspace members or `uv.toml` files.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv]
# Always install Werkzeug 2.3.0, regardless of whether transitive dependencies request
# a different version.
override-dependencies = ["werkzeug==2.3.0"]
```

---

### [`package`](#package) {: #package }

Whether the project should be considered a Python package, or a non-package ("virtual")
project.

Packages are built and installed into the virtual environment in editable mode and thus
require a build backend, while virtual projects are _not_ built or installed; instead, only
their dependencies are included in the virtual environment.

Creating a package requires that a `build-system` is present in the `pyproject.toml`, and
that the project adheres to a structure that adheres to the build backend's expectations
(e.g., a `src` layout).

**Default value**: `true`

**Type**: `bool`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv]
package = false
```

---

### [`required-environments`](#required-environments) {: #required-environments }

A list of required platforms, for packages that lack source distributions.

When a package does not have a source distribution, it's availability will be limited to
the platforms supported by its built distributions (wheels). For example, if a package only
publishes wheels for Linux, then it won't be installable on macOS or Windows.

By default, uv requires each package to include at least one wheel that is compatible with
the designated Python version. The `required-environments` setting can be used to ensure that
the resulting resolution contains wheels for specific platforms, or fails if no such wheels
are available.

While the `environments` setting _limits_ the set of environments that uv will consider when
resolving dependencies, `required-environments` _expands_ the set of platforms that uv _must_
support when resolving dependencies.

For example, `environments = ["sys_platform == 'darwin'"]` would limit uv to solving for
macOS (and ignoring Linux and Windows). On the other hand, `required-environments = ["sys_platform == 'darwin'"]`
would _require_ that any package without a source distribution include a wheel for macOS in
order to be installable.

**Default value**: `[]`

**Type**: `str | list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv]
# Require that the package is available for macOS ARM and x86 (Intel).
required-environments = [
    "sys_platform == 'darwin' and platform_machine == 'arm64'",
    "sys_platform == 'darwin' and platform_machine == 'x86_64'",
]
```

---

### [`sources`](#sources) {: #sources }

The sources to use when resolving dependencies.

`tool.uv.sources` enriches the dependency metadata with additional sources, incorporated
during development. A dependency source can be a Git repository, a URL, a local path, or an
alternative registry.

See [Dependencies](../concepts/projects/dependencies.md) for more.

**Default value**: `{}`

**Type**: `dict`

**Example usage**:

```toml title="pyproject.toml"

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx", tag = "0.27.0" }
pytest = { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl" }
pydantic = { path = "/path/to/pydantic", editable = true }
```

---

### `build-backend`

Settings for the uv build backend (`uv_build`).

Note that those settings only apply when using the `uv_build` backend, other build backends
(such as hatchling) have their own configuration.

All options that accept globs use the portable glob patterns from
[PEP 639](https://packaging.python.org/en/latest/specifications/glob-patterns/).

#### [`data`](#build-backend_data) {: #build-backend_data }
<span id="data"></span>

Data includes for wheels.

Each entry is a directory, whose contents are copied to the matching directory in the wheel
in `<name>-<version>.data/(purelib|platlib|headers|scripts|data)`. Upon installation, this
data is moved to its target location, as defined by
<https://docs.python.org/3.12/library/sysconfig.html#installation-paths>. Usually, small
data files are included by placing them in the Python module instead of using data includes.

- `scripts`: Installed to the directory for executables, `<venv>/bin` on Unix or
  `<venv>\Scripts` on Windows. This directory is added to `PATH` when the virtual
  environment  is activated or when using `uv run`, so this data type can be used to install
  additional binaries. Consider using `project.scripts` instead for Python entrypoints.
- `data`: Installed over the virtualenv environment root.

    Warning: This may override existing files!

- `headers`: Installed to the include directory. Compilers building Python packages
  with this package as build requirement use the include directory to find additional header
  files.
- `purelib` and `platlib`: Installed to the `site-packages` directory. It is not recommended
  to use these two options.

**Default value**: `{}`

**Type**: `dict[str, str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv.build-backend]
data = { headers = "include/headers", scripts = "bin" }
```

---

#### [`default-excludes`](#build-backend_default-excludes) {: #build-backend_default-excludes }
<span id="default-excludes"></span>

If set to `false`, the default excludes aren't applied.

Default excludes: `__pycache__`, `*.pyc`, and `*.pyo`.

**Default value**: `true`

**Type**: `bool`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv.build-backend]
default-excludes = false
```

---

#### [`module-name`](#build-backend_module-name) {: #build-backend_module-name }
<span id="module-name"></span>

The name of the module directory inside `module-root`.

The default module name is the package name with dots and dashes replaced by underscores.

Package names need to be valid Python identifiers, and the directory needs to contain a
`__init__.py`. An exception are stubs packages, whose name ends with `-stubs`, with the stem
being the module name, and which contain a `__init__.pyi` file.

For namespace packages with a single module, the path can be dotted, e.g., `foo.bar` or
`foo-stubs.bar`.

For namespace packages with multiple modules, the path can be a list, e.g.,
`["foo", "bar"]`. We recommend using a single module per package, splitting multiple
packages into a workspace.

Note that using this option runs the risk of creating two packages with different names but
the same module names. Installing such packages together leads to unspecified behavior,
often with corrupted files or directory trees.

**Default value**: `None`

**Type**: `str | list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv.build-backend]
module-name = "sklearn"
```

---

#### [`module-root`](#build-backend_module-root) {: #build-backend_module-root }
<span id="module-root"></span>

The directory that contains the module directory.

Common values are `src` (src layout, the default) or an empty path (flat layout).

**Default value**: `"src"`

**Type**: `str`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv.build-backend]
module-root = ""
```

---

#### [`namespace`](#build-backend_namespace) {: #build-backend_namespace }
<span id="namespace"></span>

Build a namespace package.

Build a PEP 420 implicit namespace package, allowing more than one root `__init__.py`.

Use this option when the namespace package contains multiple root `__init__.py`, for
namespace packages with a single root `__init__.py` use a dotted `module-name` instead.

To compare dotted `module-name` and `namespace = true`, the first example below can be
expressed with `module-name = "cloud.database"`: There is one root `__init__.py` `database`.
In the second example, we have three roots (`cloud.database`, `cloud.database_pro`,
`billing.modules.database_pro`), so `namespace = true` is required.

```text
src
└── cloud
    └── database
        ├── __init__.py
        ├── query_builder
        │   └── __init__.py
        └── sql
            ├── parser.py
            └── __init__.py
```

```text
src
├── cloud
│   ├── database
│   │   ├── __init__.py
│   │   ├── query_builder
│   │   │   └── __init__.py
│   │   └── sql
│   │       ├── __init__.py
│   │       └── parser.py
│   └── database_pro
│       ├── __init__.py
│       └── query_builder.py
└── billing
    └── modules
        └── database_pro
            ├── __init__.py
            └── sql.py
```

**Default value**: `false`

**Type**: `bool`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv.build-backend]
namespace = true
```

---

#### [`source-exclude`](#build-backend_source-exclude) {: #build-backend_source-exclude }
<span id="source-exclude"></span>

Glob expressions which files and directories to exclude from the source distribution.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv.build-backend]
source-exclude = ["*.bin"]
```

---

#### [`source-include`](#build-backend_source-include) {: #build-backend_source-include }
<span id="source-include"></span>

Glob expressions which files and directories to additionally include in the source
distribution.

`pyproject.toml` and the contents of the module directory are always included.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv.build-backend]
source-include = ["tests/**"]
```

---

#### [`wheel-exclude`](#build-backend_wheel-exclude) {: #build-backend_wheel-exclude }
<span id="wheel-exclude"></span>

Glob expressions which files and directories to exclude from the wheel.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv.build-backend]
wheel-exclude = ["*.bin"]
```

---

### `workspace`

#### [`exclude`](#workspace_exclude) {: #workspace_exclude }
<span id="exclude"></span>

Packages to exclude as workspace members. If a package matches both `members` and
`exclude`, it will be excluded.

Supports both globs and explicit paths.

For more information on the glob syntax, refer to the [`glob` documentation](https://docs.rs/glob/latest/glob/struct.Pattern.html).

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv.workspace]
exclude = ["member1", "path/to/member2", "libs/*"]
```

---

#### [`members`](#workspace_members) {: #workspace_members }
<span id="members"></span>

Packages to include as workspace members.

Supports both globs and explicit paths.

For more information on the glob syntax, refer to the [`glob` documentation](https://docs.rs/glob/latest/glob/struct.Pattern.html).

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

```toml title="pyproject.toml"
[tool.uv.workspace]
members = ["member1", "path/to/member2", "libs/*"]
```

---

## Configuration
### [`add-bounds`](#add-bounds) {: #add-bounds }

The default version specifier when adding a dependency.

When adding a dependency to the project, if no constraint or URL is provided, a constraint
is added based on the latest compatible version of the package. By default, a lower bound
constraint is used, e.g., `>=1.2.3`.

When `--frozen` is provided, no resolution is performed, and dependencies are always added
without constraints.

This option is in preview and may change in any future release.

**Default value**: `"lower"`

**Possible values**:

- `"lower"`: Only a lower bound, e.g., `>=1.2.3`
- `"major"`: Allow the same major version, similar to the semver caret, e.g., `>=1.2.3, <2.0.0`
- `"minor"`: Allow the same minor version, similar to the semver tilde, e.g., `>=1.2.3, <1.3.0`
- `"exact"`: Pin the exact version, e.g., `==1.2.3`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    add-bounds = "major"
    ```
=== "uv.toml"

    ```toml
    add-bounds = "major"
    ```

---

### [`allow-insecure-host`](#allow-insecure-host) {: #allow-insecure-host }

Allow insecure connections to host.

Expects to receive either a hostname (e.g., `localhost`), a host-port pair (e.g.,
`localhost:8080`), or a URL (e.g., `https://localhost`).

WARNING: Hosts included in this list will not be verified against the system's certificate
store. Only use `--allow-insecure-host` in a secure network with verified sources, as it
bypasses SSL verification and could expose you to MITM attacks.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    allow-insecure-host = ["localhost:8080"]
    ```
=== "uv.toml"

    ```toml
    allow-insecure-host = ["localhost:8080"]
    ```

---

### [`cache-dir`](#cache-dir) {: #cache-dir }

Path to the cache directory.

Defaults to `$XDG_CACHE_HOME/uv` or `$HOME/.cache/uv` on Linux and macOS, and
`%LOCALAPPDATA%\uv\cache` on Windows.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    cache-dir = "./.uv_cache"
    ```
=== "uv.toml"

    ```toml
    cache-dir = "./.uv_cache"
    ```

---

### [`cache-keys`](#cache-keys) {: #cache-keys }

The keys to consider when caching builds for the project.

Cache keys enable you to specify the files or directories that should trigger a rebuild when
modified. By default, uv will rebuild a project whenever the `pyproject.toml`, `setup.py`,
or `setup.cfg` files in the project directory are modified, or if a `src` directory is
added or removed, i.e.:

```toml
cache-keys = [{ file = "pyproject.toml" }, { file = "setup.py" }, { file = "setup.cfg" }, { dir = "src" }]
```

As an example: if a project uses dynamic metadata to read its dependencies from a
`requirements.txt` file, you can specify `cache-keys = [{ file = "requirements.txt" }, { file = "pyproject.toml" }]`
to ensure that the project is rebuilt whenever the `requirements.txt` file is modified (in
addition to watching the `pyproject.toml`).

Globs are supported, following the syntax of the [`glob`](https://docs.rs/glob/0.3.1/glob/struct.Pattern.html)
crate. For example, to invalidate the cache whenever a `.toml` file in the project directory
or any of its subdirectories is modified, you can specify `cache-keys = [{ file = "**/*.toml" }]`.
Note that the use of globs can be expensive, as uv may need to walk the filesystem to
determine whether any files have changed.

Cache keys can also include version control information. For example, if a project uses
`setuptools_scm` to read its version from a Git commit, you can specify `cache-keys = [{ git = { commit = true }, { file = "pyproject.toml" }]`
to include the current Git commit hash in the cache key (in addition to the
`pyproject.toml`). Git tags are also supported via `cache-keys = [{ git = { commit = true, tags = true } }]`.

Cache keys can also include environment variables. For example, if a project relies on
`MACOSX_DEPLOYMENT_TARGET` or other environment variables to determine its behavior, you can
specify `cache-keys = [{ env = "MACOSX_DEPLOYMENT_TARGET" }]` to invalidate the cache
whenever the environment variable changes.

Cache keys only affect the project defined by the `pyproject.toml` in which they're
specified (as opposed to, e.g., affecting all members in a workspace), and all paths and
globs are interpreted as relative to the project directory.

**Default value**: `[{ file = "pyproject.toml" }, { file = "setup.py" }, { file = "setup.cfg" }]`

**Type**: `list[dict]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    cache-keys = [{ file = "pyproject.toml" }, { file = "requirements.txt" }, { git = { commit = true } }]
    ```
=== "uv.toml"

    ```toml
    cache-keys = [{ file = "pyproject.toml" }, { file = "requirements.txt" }, { git = { commit = true } }]
    ```

---

### [`check-url`](#check-url) {: #check-url }

Check an index URL for existing files to skip duplicate uploads.

This option allows retrying publishing that failed after only some, but not all files have
been uploaded, and handles error due to parallel uploads of the same file.

Before uploading, the index is checked. If the exact same file already exists in the index,
the file will not be uploaded. If an error occurred during the upload, the index is checked
again, to handle cases where the identical file was uploaded twice in parallel.

The exact behavior will vary based on the index. When uploading to PyPI, uploading the same
file succeeds even without `--check-url`, while most other indexes error.

The index must provide one of the supported hashes (SHA-256, SHA-384, or SHA-512).

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    check-url = "https://test.pypi.org/simple"
    ```
=== "uv.toml"

    ```toml
    check-url = "https://test.pypi.org/simple"
    ```

---

### [`compile-bytecode`](#compile-bytecode) {: #compile-bytecode }

Compile Python files to bytecode after installation.

By default, uv does not compile Python (`.py`) files to bytecode (`__pycache__/*.pyc`);
instead, compilation is performed lazily the first time a module is imported. For use-cases
in which start time is critical, such as CLI applications and Docker containers, this option
can be enabled to trade longer installation times for faster start times.

When enabled, uv will process the entire site-packages directory (including packages that
are not being modified by the current operation) for consistency. Like pip, it will also
ignore errors.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    compile-bytecode = true
    ```
=== "uv.toml"

    ```toml
    compile-bytecode = true
    ```

---

### [`concurrent-builds`](#concurrent-builds) {: #concurrent-builds }

The maximum number of source distributions that uv will build concurrently at any given
time.

Defaults to the number of available CPU cores.

**Default value**: `None`

**Type**: `int`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    concurrent-builds = 4
    ```
=== "uv.toml"

    ```toml
    concurrent-builds = 4
    ```

---

### [`concurrent-downloads`](#concurrent-downloads) {: #concurrent-downloads }

The maximum number of in-flight concurrent downloads that uv will perform at any given
time.

**Default value**: `50`

**Type**: `int`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    concurrent-downloads = 4
    ```
=== "uv.toml"

    ```toml
    concurrent-downloads = 4
    ```

---

### [`concurrent-installs`](#concurrent-installs) {: #concurrent-installs }

The number of threads used when installing and unzipping packages.

Defaults to the number of available CPU cores.

**Default value**: `None`

**Type**: `int`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    concurrent-installs = 4
    ```
=== "uv.toml"

    ```toml
    concurrent-installs = 4
    ```

---

### [`config-settings`](#config-settings) {: #config-settings }

Settings to pass to the [PEP 517](https://peps.python.org/pep-0517/) build backend,
specified as `KEY=VALUE` pairs.

**Default value**: `{}`

**Type**: `dict`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    config-settings = { editable_mode = "compat" }
    ```
=== "uv.toml"

    ```toml
    config-settings = { editable_mode = "compat" }
    ```

---

### [`config-settings-package`](#config-settings-package) {: #config-settings-package }

Settings to pass to the [PEP 517](https://peps.python.org/pep-0517/) build backend for specific packages,
specified as `KEY=VALUE` pairs.

Accepts a map from package names to string key-value pairs.

**Default value**: `{}`

**Type**: `dict`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    config-settings-package = { numpy = { editable_mode = "compat" } }
    ```
=== "uv.toml"

    ```toml
    config-settings-package = { numpy = { editable_mode = "compat" } }
    ```

---

### [`dependency-metadata`](#dependency-metadata) {: #dependency-metadata }

Pre-defined static metadata for dependencies of the project (direct or transitive). When
provided, enables the resolver to use the specified metadata instead of querying the
registry or building the relevant package from source.

Metadata should be provided in adherence with the [Metadata 2.3](https://packaging.python.org/en/latest/specifications/core-metadata/)
standard, though only the following fields are respected:

- `name`: The name of the package.
- (Optional) `version`: The version of the package. If omitted, the metadata will be applied
  to all versions of the package.
- (Optional) `requires-dist`: The dependencies of the package (e.g., `werkzeug>=0.14`).
- (Optional) `requires-python`: The Python version required by the package (e.g., `>=3.10`).
- (Optional) `provides-extra`: The extras provided by the package.

**Default value**: `[]`

**Type**: `list[dict]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    dependency-metadata = [
        { name = "flask", version = "1.0.0", requires-dist = ["werkzeug"], requires-python = ">=3.6" },
    ]
    ```
=== "uv.toml"

    ```toml
    dependency-metadata = [
        { name = "flask", version = "1.0.0", requires-dist = ["werkzeug"], requires-python = ">=3.6" },
    ]
    ```

---

### [`exclude-newer`](#exclude-newer) {: #exclude-newer }

Limit candidate packages to those that were uploaded prior to a given point in time.

Accepts a superset of [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html) (e.g.,
`2006-12-02T02:07:43Z`). A full timestamp is required to ensure that the resolver will
behave consistently across timezones.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    exclude-newer = "2006-12-02T02:07:43Z"
    ```
=== "uv.toml"

    ```toml
    exclude-newer = "2006-12-02T02:07:43Z"
    ```

---

### [`exclude-newer-package`](#exclude-newer-package) {: #exclude-newer-package }

Limit candidate packages for specific packages to those that were uploaded prior to the given date.

Accepts package-date pairs in a dictionary format.

**Default value**: `None`

**Type**: `dict`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    exclude-newer-package = { tqdm = "2022-04-04T00:00:00Z" }
    ```
=== "uv.toml"

    ```toml
    exclude-newer-package = { tqdm = "2022-04-04T00:00:00Z" }
    ```

---

### [`extra-build-dependencies`](#extra-build-dependencies) {: #extra-build-dependencies }

Additional build dependencies for packages.

This allows extending the PEP 517 build environment for the project's dependencies with
additional packages. This is useful for packages that assume the presence of packages like
`pip`, and do not declare them as build dependencies.

**Default value**: `[]`

**Type**: `dict`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    extra-build-dependencies = { pytest = ["setuptools"] }
    ```
=== "uv.toml"

    ```toml
    extra-build-dependencies = { pytest = ["setuptools"] }
    ```

---

### [`extra-build-variables`](#extra-build-variables) {: #extra-build-variables }

Extra environment variables to set when building certain packages.

Environment variables will be added to the environment when building the
specified packages.

**Default value**: `{}`

**Type**: `dict[str, dict[str, str]]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } }
    ```
=== "uv.toml"

    ```toml
    extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } }
    ```

---

### [`extra-index-url`](#extra-index-url) {: #extra-index-url }

Extra URLs of package indexes to use, in addition to `--index-url`.

Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
(the simple repository API), or a local directory laid out in the same format.

All indexes provided via this flag take priority over the index specified by
[`index_url`](#index-url) or [`index`](#index) with `default = true`. When multiple indexes
are provided, earlier values take priority.

To control uv's resolution strategy when multiple indexes are present, see
[`index_strategy`](#index-strategy).

(Deprecated: use `index` instead.)

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    extra-index-url = ["https://download.pytorch.org/whl/cpu"]
    ```
=== "uv.toml"

    ```toml
    extra-index-url = ["https://download.pytorch.org/whl/cpu"]
    ```

---

### [`find-links`](#find-links) {: #find-links }

Locations to search for candidate distributions, in addition to those found in the registry
indexes.

If a path, the target must be a directory that contains packages as wheel files (`.whl`) or
source distributions (e.g., `.tar.gz` or `.zip`) at the top level.

If a URL, the page must contain a flat list of links to package files adhering to the
formats described above.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    find-links = ["https://download.pytorch.org/whl/torch_stable.html"]
    ```
=== "uv.toml"

    ```toml
    find-links = ["https://download.pytorch.org/whl/torch_stable.html"]
    ```

---

### [`fork-strategy`](#fork-strategy) {: #fork-strategy }

The strategy to use when selecting multiple versions of a given package across Python
versions and platforms.

By default, uv will optimize for selecting the latest version of each package for each
supported Python version (`requires-python`), while minimizing the number of selected
versions across platforms.

Under `fewest`, uv will minimize the number of selected versions for each package,
preferring older versions that are compatible with a wider range of supported Python
versions or platforms.

**Default value**: `"requires-python"`

**Possible values**:

- `"fewest"`: Optimize for selecting the fewest number of versions for each package. Older versions may be preferred if they are compatible with a wider range of supported Python versions or platforms
- `"requires-python"`: Optimize for selecting latest supported version of each package, for each supported Python version

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    fork-strategy = "fewest"
    ```
=== "uv.toml"

    ```toml
    fork-strategy = "fewest"
    ```

---

### [`index`](#index) {: #index }

The package indexes to use when resolving dependencies.

Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
(the simple repository API), or a local directory laid out in the same format.

Indexes are considered in the order in which they're defined, such that the first-defined
index has the highest priority. Further, the indexes provided by this setting are given
higher priority than any indexes specified via [`index_url`](#index-url) or
[`extra_index_url`](#extra-index-url). uv will only consider the first index that contains
a given package, unless an alternative [index strategy](#index-strategy) is specified.

If an index is marked as `explicit = true`, it will be used exclusively for those
dependencies that select it explicitly via `[tool.uv.sources]`, as in:

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

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

If an index is marked as `default = true`, it will be moved to the end of the prioritized list, such that it is
given the lowest priority when resolving packages. Additionally, marking an index as default will disable the
PyPI default index.

**Default value**: `"[]"`

**Type**: `dict`

**Example usage**:

=== "pyproject.toml"

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

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

---

### [`index-strategy`](#index-strategy) {: #index-strategy }

The strategy to use when resolving against multiple index URLs.

By default, uv will stop at the first index on which a given package is available, and
limit resolutions to those present on that first index (`first-index`). This prevents
"dependency confusion" attacks, whereby an attacker can upload a malicious package under the
same name to an alternate index.

**Default value**: `"first-index"`

**Possible values**:

- `"first-index"`: Only use results from the first index that returns a match for a given package name
- `"unsafe-first-match"`: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next
- `"unsafe-best-match"`: Search for every package name across all indexes, preferring the "best" version found. If a package version is in multiple indexes, only look at the entry for the first index

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    index-strategy = "unsafe-best-match"
    ```
=== "uv.toml"

    ```toml
    index-strategy = "unsafe-best-match"
    ```

---

### [`index-url`](#index-url) {: #index-url }

The URL of the Python package index (by default: <https://pypi.org/simple>).

Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
(the simple repository API), or a local directory laid out in the same format.

The index provided by this setting is given lower priority than any indexes specified via
[`extra_index_url`](#extra-index-url) or [`index`](#index).

(Deprecated: use `index` instead.)

**Default value**: `"https://pypi.org/simple"`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    index-url = "https://test.pypi.org/simple"
    ```
=== "uv.toml"

    ```toml
    index-url = "https://test.pypi.org/simple"
    ```

---

### [`keyring-provider`](#keyring-provider) {: #keyring-provider }

Attempt to use `keyring` for authentication for index URLs.

At present, only `--keyring-provider subprocess` is supported, which configures uv to
use the `keyring` CLI to handle authentication.

**Default value**: `"disabled"`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    keyring-provider = "subprocess"
    ```
=== "uv.toml"

    ```toml
    keyring-provider = "subprocess"
    ```

---

### [`link-mode`](#link-mode) {: #link-mode }

The method to use when installing packages from the global cache.

Defaults to `clone` (also known as Copy-on-Write) on macOS, and `hardlink` on Linux and
Windows.

WARNING: The use of symlink link mode is discouraged, as they create tight coupling between
the cache and the target environment. For example, clearing the cache (`uv cache clean`)
will break all installed packages by way of removing the underlying source files. Use
symlinks with caution.

**Default value**: `"clone" (macOS) or "hardlink" (Linux, Windows)`

**Possible values**:

- `"clone"`: Clone (i.e., copy-on-write) packages from the wheel into the `site-packages` directory
- `"copy"`: Copy packages from the wheel into the `site-packages` directory
- `"hardlink"`: Hard link packages from the wheel into the `site-packages` directory
- `"symlink"`: Symbolically link packages from the wheel into the `site-packages` directory

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    link-mode = "copy"
    ```
=== "uv.toml"

    ```toml
    link-mode = "copy"
    ```

---

### [`native-tls`](#native-tls) {: #native-tls }

Whether to load TLS certificates from the platform's native certificate store.

By default, uv loads certificates from the bundled `webpki-roots` crate. The
`webpki-roots` are a reliable set of trust roots from Mozilla, and including them in uv
improves portability and performance (especially on macOS).

However, in some cases, you may want to use the platform's native certificate store,
especially if you're relying on a corporate trust root (e.g., for a mandatory proxy) that's
included in your system's certificate store.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    native-tls = true
    ```
=== "uv.toml"

    ```toml
    native-tls = true
    ```

---

### [`no-binary`](#no-binary) {: #no-binary }

Don't install pre-built wheels.

The given packages will be built and installed from source. The resolver will still use
pre-built wheels to extract package metadata, if available.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    no-binary = true
    ```
=== "uv.toml"

    ```toml
    no-binary = true
    ```

---

### [`no-binary-package`](#no-binary-package) {: #no-binary-package }

Don't install pre-built wheels for a specific package.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    no-binary-package = ["ruff"]
    ```
=== "uv.toml"

    ```toml
    no-binary-package = ["ruff"]
    ```

---

### [`no-build`](#no-build) {: #no-build }

Don't build source distributions.

When enabled, resolving will not run arbitrary Python code. The cached wheels of
already-built source distributions will be reused, but operations that require building
distributions will exit with an error.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    no-build = true
    ```
=== "uv.toml"

    ```toml
    no-build = true
    ```

---

### [`no-build-isolation`](#no-build-isolation) {: #no-build-isolation }

Disable isolation when building source distributions.

Assumes that build dependencies specified by [PEP 518](https://peps.python.org/pep-0518/)
are already installed.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    no-build-isolation = true
    ```
=== "uv.toml"

    ```toml
    no-build-isolation = true
    ```

---

### [`no-build-isolation-package`](#no-build-isolation-package) {: #no-build-isolation-package }

Disable isolation when building source distributions for a specific package.

Assumes that the packages' build dependencies specified by [PEP 518](https://peps.python.org/pep-0518/)
are already installed.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    no-build-isolation-package = ["package1", "package2"]
    ```
=== "uv.toml"

    ```toml
    no-build-isolation-package = ["package1", "package2"]
    ```

---

### [`no-build-package`](#no-build-package) {: #no-build-package }

Don't build source distributions for a specific package.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    no-build-package = ["ruff"]
    ```
=== "uv.toml"

    ```toml
    no-build-package = ["ruff"]
    ```

---

### [`no-cache`](#no-cache) {: #no-cache }

Avoid reading from or writing to the cache, instead using a temporary directory for the
duration of the operation.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    no-cache = true
    ```
=== "uv.toml"

    ```toml
    no-cache = true
    ```

---

### [`no-index`](#no-index) {: #no-index }

Ignore all registry indexes (e.g., PyPI), instead relying on direct URL dependencies and
those provided via `--find-links`.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    no-index = true
    ```
=== "uv.toml"

    ```toml
    no-index = true
    ```

---

### [`no-sources`](#no-sources) {: #no-sources }

Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
standards-compliant, publishable package metadata, as opposed to using any local or Git
sources.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    no-sources = true
    ```
=== "uv.toml"

    ```toml
    no-sources = true
    ```

---

### [`offline`](#offline) {: #offline }

Disable network access, relying only on locally cached data and locally available files.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    offline = true
    ```
=== "uv.toml"

    ```toml
    offline = true
    ```

---

### [`prerelease`](#prerelease) {: #prerelease }

The strategy to use when considering pre-release versions.

By default, uv will accept pre-releases for packages that _only_ publish pre-releases,
along with first-party requirements that contain an explicit pre-release marker in the
declared specifiers (`if-necessary-or-explicit`).

**Default value**: `"if-necessary-or-explicit"`

**Possible values**:

- `"disallow"`: Disallow all pre-release versions
- `"allow"`: Allow all pre-release versions
- `"if-necessary"`: Allow pre-release versions if all versions of a package are pre-release
- `"explicit"`: Allow pre-release versions for first-party packages with explicit pre-release markers in their version requirements
- `"if-necessary-or-explicit"`: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    prerelease = "allow"
    ```
=== "uv.toml"

    ```toml
    prerelease = "allow"
    ```

---

### [`preview`](#preview) {: #preview }

Whether to enable experimental, preview features.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    preview = true
    ```
=== "uv.toml"

    ```toml
    preview = true
    ```

---

### [`publish-url`](#publish-url) {: #publish-url }

The URL for publishing packages to the Python package index (by default:
<https://upload.pypi.org/legacy/>).

**Default value**: `"https://upload.pypi.org/legacy/"`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    publish-url = "https://test.pypi.org/legacy/"
    ```
=== "uv.toml"

    ```toml
    publish-url = "https://test.pypi.org/legacy/"
    ```

---

### [`pypy-install-mirror`](#pypy-install-mirror) {: #pypy-install-mirror }

Mirror URL to use for downloading managed PyPy installations.

By default, managed PyPy installations are downloaded from [downloads.python.org](https://downloads.python.org/).
This variable can be set to a mirror URL to use a different source for PyPy installations.
The provided URL will replace `https://downloads.python.org/pypy` in, e.g., `https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`.

Distributions can be read from a
local directory by using the `file://` URL scheme.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    pypy-install-mirror = "https://downloads.python.org/pypy"
    ```
=== "uv.toml"

    ```toml
    pypy-install-mirror = "https://downloads.python.org/pypy"
    ```

---

### [`python-downloads`](#python-downloads) {: #python-downloads }

Whether to allow Python downloads.

**Default value**: `"automatic"`

**Possible values**:

- `"automatic"`: Automatically download managed Python installations when needed
- `"manual"`: Do not automatically download managed Python installations; require explicit installation
- `"never"`: Do not ever allow Python downloads

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    python-downloads = "manual"
    ```
=== "uv.toml"

    ```toml
    python-downloads = "manual"
    ```

---

### [`python-downloads-json-url`](#python-downloads-json-url) {: #python-downloads-json-url }

URL pointing to JSON of custom Python installations.

Note that currently, only local paths are supported.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    python-downloads-json-url = "/etc/uv/python-downloads.json"
    ```
=== "uv.toml"

    ```toml
    python-downloads-json-url = "/etc/uv/python-downloads.json"
    ```

---

### [`python-install-mirror`](#python-install-mirror) {: #python-install-mirror }

Mirror URL for downloading managed Python installations.

By default, managed Python installations are downloaded from [`python-build-standalone`](https://github.com/astral-sh/python-build-standalone).
This variable can be set to a mirror URL to use a different source for Python installations.
The provided URL will replace `https://github.com/astral-sh/python-build-standalone/releases/download` in, e.g., `https://github.com/astral-sh/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`.

Distributions can be read from a local directory by using the `file://` URL scheme.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    python-install-mirror = "https://github.com/astral-sh/python-build-standalone/releases/download"
    ```
=== "uv.toml"

    ```toml
    python-install-mirror = "https://github.com/astral-sh/python-build-standalone/releases/download"
    ```

---

### [`python-preference`](#python-preference) {: #python-preference }

Whether to prefer using Python installations that are already present on the system, or
those that are downloaded and installed by uv.

**Default value**: `"managed"`

**Possible values**:

- `"only-managed"`: Only use managed Python installations; never use system Python installations
- `"managed"`: Prefer managed Python installations over system Python installations
- `"system"`: Prefer system Python installations over managed Python installations
- `"only-system"`: Only use system Python installations; never use managed Python installations

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    python-preference = "managed"
    ```
=== "uv.toml"

    ```toml
    python-preference = "managed"
    ```

---

### [`reinstall`](#reinstall) {: #reinstall }

Reinstall all packages, regardless of whether they're already installed. Implies `refresh`.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    reinstall = true
    ```
=== "uv.toml"

    ```toml
    reinstall = true
    ```

---

### [`reinstall-package`](#reinstall-package) {: #reinstall-package }

Reinstall a specific package, regardless of whether it's already installed. Implies
`refresh-package`.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    reinstall-package = ["ruff"]
    ```
=== "uv.toml"

    ```toml
    reinstall-package = ["ruff"]
    ```

---

### [`required-version`](#required-version) {: #required-version }

Enforce a requirement on the version of uv.

If the version of uv does not meet the requirement at runtime, uv will exit
with an error.

Accepts a [PEP 440](https://peps.python.org/pep-0440/) specifier, like `==0.5.0` or `>=0.5.0`.

**Default value**: `null`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    required-version = ">=0.5.0"
    ```
=== "uv.toml"

    ```toml
    required-version = ">=0.5.0"
    ```

---

### [`resolution`](#resolution) {: #resolution }

The strategy to use when selecting between the different compatible versions for a given
package requirement.

By default, uv will use the latest compatible version of each package (`highest`).

**Default value**: `"highest"`

**Possible values**:

- `"highest"`: Resolve the highest compatible version of each package
- `"lowest"`: Resolve the lowest compatible version of each package
- `"lowest-direct"`: Resolve the lowest compatible version of any direct dependencies, and the highest compatible version of any transitive dependencies

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    resolution = "lowest-direct"
    ```
=== "uv.toml"

    ```toml
    resolution = "lowest-direct"
    ```

---

### [`trusted-publishing`](#trusted-publishing) {: #trusted-publishing }

Configure trusted publishing.

By default, uv checks for trusted publishing when running in a supported environment, but
ignores it if it isn't configured.

uv's supported environments for trusted publishing include GitHub Actions and GitLab CI/CD.

**Default value**: `automatic`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    trusted-publishing = "always"
    ```
=== "uv.toml"

    ```toml
    trusted-publishing = "always"
    ```

---

### [`upgrade`](#upgrade) {: #upgrade }

Allow package upgrades, ignoring pinned versions in any existing output file.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    upgrade = true
    ```
=== "uv.toml"

    ```toml
    upgrade = true
    ```

---

### [`upgrade-package`](#upgrade-package) {: #upgrade-package }

Allow upgrades for a specific package, ignoring pinned versions in any existing output
file.

Accepts both standalone package names (`ruff`) and version specifiers (`ruff<0.5.0`).

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv]
    upgrade-package = ["ruff"]
    ```
=== "uv.toml"

    ```toml
    upgrade-package = ["ruff"]
    ```

---

### `pip`

Settings that are specific to the `uv pip` command-line interface.

These values will be ignored when running commands outside the `uv pip` namespace (e.g.,
`uv lock`, `uvx`).

#### [`all-extras`](#pip_all-extras) {: #pip_all-extras }
<span id="all-extras"></span>

Include all optional dependencies.

Only applies to `pyproject.toml`, `setup.py`, and `setup.cfg` sources.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    all-extras = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    all-extras = true
    ```

---

#### [`allow-empty-requirements`](#pip_allow-empty-requirements) {: #pip_allow-empty-requirements }
<span id="allow-empty-requirements"></span>

Allow `uv pip sync` with empty requirements, which will clear the environment of all
packages.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    allow-empty-requirements = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    allow-empty-requirements = true
    ```

---

#### [`annotation-style`](#pip_annotation-style) {: #pip_annotation-style }
<span id="annotation-style"></span>

The style of the annotation comments included in the output file, used to indicate the
source of each package.

**Default value**: `"split"`

**Possible values**:

- `"line"`: Render the annotations on a single, comma-separated line
- `"split"`: Render each annotation on its own line

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    annotation-style = "line"
    ```
=== "uv.toml"

    ```toml
    [pip]
    annotation-style = "line"
    ```

---

#### [`break-system-packages`](#pip_break-system-packages) {: #pip_break-system-packages }
<span id="break-system-packages"></span>

Allow uv to modify an `EXTERNALLY-MANAGED` Python installation.

WARNING: `--break-system-packages` is intended for use in continuous integration (CI)
environments, when installing into Python installations that are managed by an external
package manager, like `apt`. It should be used with caution, as such Python installations
explicitly recommend against modifications by other package managers (like uv or pip).

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    break-system-packages = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    break-system-packages = true
    ```

---

#### [`compile-bytecode`](#pip_compile-bytecode) {: #pip_compile-bytecode }
<span id="compile-bytecode"></span>

Compile Python files to bytecode after installation.

By default, uv does not compile Python (`.py`) files to bytecode (`__pycache__/*.pyc`);
instead, compilation is performed lazily the first time a module is imported. For use-cases
in which start time is critical, such as CLI applications and Docker containers, this option
can be enabled to trade longer installation times for faster start times.

When enabled, uv will process the entire site-packages directory (including packages that
are not being modified by the current operation) for consistency. Like pip, it will also
ignore errors.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    compile-bytecode = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    compile-bytecode = true
    ```

---

#### [`config-settings`](#pip_config-settings) {: #pip_config-settings }
<span id="config-settings"></span>

Settings to pass to the [PEP 517](https://peps.python.org/pep-0517/) build backend,
specified as `KEY=VALUE` pairs.

**Default value**: `{}`

**Type**: `dict`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    config-settings = { editable_mode = "compat" }
    ```
=== "uv.toml"

    ```toml
    [pip]
    config-settings = { editable_mode = "compat" }
    ```

---

#### [`config-settings-package`](#pip_config-settings-package) {: #pip_config-settings-package }
<span id="config-settings-package"></span>

Settings to pass to the [PEP 517](https://peps.python.org/pep-0517/) build backend for specific packages,
specified as `KEY=VALUE` pairs.

**Default value**: `{}`

**Type**: `dict`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    config-settings-package = { numpy = { editable_mode = "compat" } }
    ```
=== "uv.toml"

    ```toml
    [pip]
    config-settings-package = { numpy = { editable_mode = "compat" } }
    ```

---

#### [`custom-compile-command`](#pip_custom-compile-command) {: #pip_custom-compile-command }
<span id="custom-compile-command"></span>

The header comment to include at the top of the output file generated by `uv pip compile`.

Used to reflect custom build scripts and commands that wrap `uv pip compile`.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    custom-compile-command = "./custom-uv-compile.sh"
    ```
=== "uv.toml"

    ```toml
    [pip]
    custom-compile-command = "./custom-uv-compile.sh"
    ```

---

#### [`dependency-metadata`](#pip_dependency-metadata) {: #pip_dependency-metadata }
<span id="dependency-metadata"></span>

Pre-defined static metadata for dependencies of the project (direct or transitive). When
provided, enables the resolver to use the specified metadata instead of querying the
registry or building the relevant package from source.

Metadata should be provided in adherence with the [Metadata 2.3](https://packaging.python.org/en/latest/specifications/core-metadata/)
standard, though only the following fields are respected:

- `name`: The name of the package.
- (Optional) `version`: The version of the package. If omitted, the metadata will be applied
  to all versions of the package.
- (Optional) `requires-dist`: The dependencies of the package (e.g., `werkzeug>=0.14`).
- (Optional) `requires-python`: The Python version required by the package (e.g., `>=3.10`).
- (Optional) `provides-extra`: The extras provided by the package.

**Default value**: `[]`

**Type**: `list[dict]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    dependency-metadata = [
        { name = "flask", version = "1.0.0", requires-dist = ["werkzeug"], requires-python = ">=3.6" },
    ]
    ```
=== "uv.toml"

    ```toml
    [pip]
    dependency-metadata = [
        { name = "flask", version = "1.0.0", requires-dist = ["werkzeug"], requires-python = ">=3.6" },
    ]
    ```

---

#### [`emit-build-options`](#pip_emit-build-options) {: #pip_emit-build-options }
<span id="emit-build-options"></span>

Include `--no-binary` and `--only-binary` entries in the output file generated by `uv pip compile`.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    emit-build-options = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    emit-build-options = true
    ```

---

#### [`emit-find-links`](#pip_emit-find-links) {: #pip_emit-find-links }
<span id="emit-find-links"></span>

Include `--find-links` entries in the output file generated by `uv pip compile`.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    emit-find-links = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    emit-find-links = true
    ```

---

#### [`emit-index-annotation`](#pip_emit-index-annotation) {: #pip_emit-index-annotation }
<span id="emit-index-annotation"></span>

Include comment annotations indicating the index used to resolve each package (e.g.,
`# from https://pypi.org/simple`).

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    emit-index-annotation = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    emit-index-annotation = true
    ```

---

#### [`emit-index-url`](#pip_emit-index-url) {: #pip_emit-index-url }
<span id="emit-index-url"></span>

Include `--index-url` and `--extra-index-url` entries in the output file generated by `uv pip compile`.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    emit-index-url = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    emit-index-url = true
    ```

---

#### [`emit-marker-expression`](#pip_emit-marker-expression) {: #pip_emit-marker-expression }
<span id="emit-marker-expression"></span>

Whether to emit a marker string indicating the conditions under which the set of pinned
dependencies is valid.

The pinned dependencies may be valid even when the marker expression is
false, but when the expression is true, the requirements are known to
be correct.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    emit-marker-expression = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    emit-marker-expression = true
    ```

---

#### [`exclude-newer`](#pip_exclude-newer) {: #pip_exclude-newer }
<span id="exclude-newer"></span>

Limit candidate packages to those that were uploaded prior to a given point in time.

Accepts a superset of [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html) (e.g.,
`2006-12-02T02:07:43Z`). A full timestamp is required to ensure that the resolver will
behave consistently across timezones.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    exclude-newer = "2006-12-02T02:07:43Z"
    ```
=== "uv.toml"

    ```toml
    [pip]
    exclude-newer = "2006-12-02T02:07:43Z"
    ```

---

#### [`exclude-newer-package`](#pip_exclude-newer-package) {: #pip_exclude-newer-package }
<span id="exclude-newer-package"></span>

Limit candidate packages for specific packages to those that were uploaded prior to the given date.

Accepts package-date pairs in a dictionary format.

**Default value**: `None`

**Type**: `dict`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    exclude-newer-package = { tqdm = "2022-04-04T00:00:00Z" }
    ```
=== "uv.toml"

    ```toml
    [pip]
    exclude-newer-package = { tqdm = "2022-04-04T00:00:00Z" }
    ```

---

#### [`extra`](#pip_extra) {: #pip_extra }
<span id="extra"></span>

Include optional dependencies from the specified extra; may be provided more than once.

Only applies to `pyproject.toml`, `setup.py`, and `setup.cfg` sources.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    extra = ["dev", "docs"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    extra = ["dev", "docs"]
    ```

---

#### [`extra-build-dependencies`](#pip_extra-build-dependencies) {: #pip_extra-build-dependencies }
<span id="extra-build-dependencies"></span>

Additional build dependencies for packages.

This allows extending the PEP 517 build environment for the project's dependencies with
additional packages. This is useful for packages that assume the presence of packages like
`pip`, and do not declare them as build dependencies.

**Default value**: `[]`

**Type**: `dict`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    extra-build-dependencies = { pytest = ["setuptools"] }
    ```
=== "uv.toml"

    ```toml
    [pip]
    extra-build-dependencies = { pytest = ["setuptools"] }
    ```

---

#### [`extra-build-variables`](#pip_extra-build-variables) {: #pip_extra-build-variables }
<span id="extra-build-variables"></span>

Extra environment variables to set when building certain packages.

Environment variables will be added to the environment when building the
specified packages.

**Default value**: `{}`

**Type**: `dict[str, dict[str, str]]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } }
    ```
=== "uv.toml"

    ```toml
    [pip]
    extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } }
    ```

---

#### [`extra-index-url`](#pip_extra-index-url) {: #pip_extra-index-url }
<span id="extra-index-url"></span>

Extra URLs of package indexes to use, in addition to `--index-url`.

Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
(the simple repository API), or a local directory laid out in the same format.

All indexes provided via this flag take priority over the index specified by
[`index_url`](#index-url). When multiple indexes are provided, earlier values take priority.

To control uv's resolution strategy when multiple indexes are present, see
[`index_strategy`](#index-strategy).

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    extra-index-url = ["https://download.pytorch.org/whl/cpu"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    extra-index-url = ["https://download.pytorch.org/whl/cpu"]
    ```

---

#### [`find-links`](#pip_find-links) {: #pip_find-links }
<span id="find-links"></span>

Locations to search for candidate distributions, in addition to those found in the registry
indexes.

If a path, the target must be a directory that contains packages as wheel files (`.whl`) or
source distributions (e.g., `.tar.gz` or `.zip`) at the top level.

If a URL, the page must contain a flat list of links to package files adhering to the
formats described above.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    find-links = ["https://download.pytorch.org/whl/torch_stable.html"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    find-links = ["https://download.pytorch.org/whl/torch_stable.html"]
    ```

---

#### [`fork-strategy`](#pip_fork-strategy) {: #pip_fork-strategy }
<span id="fork-strategy"></span>

The strategy to use when selecting multiple versions of a given package across Python
versions and platforms.

By default, uv will optimize for selecting the latest version of each package for each
supported Python version (`requires-python`), while minimizing the number of selected
versions across platforms.

Under `fewest`, uv will minimize the number of selected versions for each package,
preferring older versions that are compatible with a wider range of supported Python
versions or platforms.

**Default value**: `"requires-python"`

**Possible values**:

- `"fewest"`: Optimize for selecting the fewest number of versions for each package. Older versions may be preferred if they are compatible with a wider range of supported Python versions or platforms
- `"requires-python"`: Optimize for selecting latest supported version of each package, for each supported Python version

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    fork-strategy = "fewest"
    ```
=== "uv.toml"

    ```toml
    [pip]
    fork-strategy = "fewest"
    ```

---

#### [`generate-hashes`](#pip_generate-hashes) {: #pip_generate-hashes }
<span id="generate-hashes"></span>

Include distribution hashes in the output file.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    generate-hashes = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    generate-hashes = true
    ```

---

#### [`group`](#pip_group) {: #pip_group }
<span id="group"></span>

Include the following dependency groups.

**Default value**: `None`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    group = ["dev", "docs"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    group = ["dev", "docs"]
    ```

---

#### [`index-strategy`](#pip_index-strategy) {: #pip_index-strategy }
<span id="index-strategy"></span>

The strategy to use when resolving against multiple index URLs.

By default, uv will stop at the first index on which a given package is available, and
limit resolutions to those present on that first index (`first-index`). This prevents
"dependency confusion" attacks, whereby an attacker can upload a malicious package under the
same name to an alternate index.

**Default value**: `"first-index"`

**Possible values**:

- `"first-index"`: Only use results from the first index that returns a match for a given package name
- `"unsafe-first-match"`: Search for every package name across all indexes, exhausting the versions from the first index before moving on to the next
- `"unsafe-best-match"`: Search for every package name across all indexes, preferring the "best" version found. If a package version is in multiple indexes, only look at the entry for the first index

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    index-strategy = "unsafe-best-match"
    ```
=== "uv.toml"

    ```toml
    [pip]
    index-strategy = "unsafe-best-match"
    ```

---

#### [`index-url`](#pip_index-url) {: #pip_index-url }
<span id="index-url"></span>

The URL of the Python package index (by default: <https://pypi.org/simple>).

Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
(the simple repository API), or a local directory laid out in the same format.

The index provided by this setting is given lower priority than any indexes specified via
[`extra_index_url`](#extra-index-url).

**Default value**: `"https://pypi.org/simple"`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    index-url = "https://test.pypi.org/simple"
    ```
=== "uv.toml"

    ```toml
    [pip]
    index-url = "https://test.pypi.org/simple"
    ```

---

#### [`keyring-provider`](#pip_keyring-provider) {: #pip_keyring-provider }
<span id="keyring-provider"></span>

Attempt to use `keyring` for authentication for index URLs.

At present, only `--keyring-provider subprocess` is supported, which configures uv to
use the `keyring` CLI to handle authentication.

**Default value**: `disabled`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    keyring-provider = "subprocess"
    ```
=== "uv.toml"

    ```toml
    [pip]
    keyring-provider = "subprocess"
    ```

---

#### [`link-mode`](#pip_link-mode) {: #pip_link-mode }
<span id="link-mode"></span>

The method to use when installing packages from the global cache.

Defaults to `clone` (also known as Copy-on-Write) on macOS, and `hardlink` on Linux and
Windows.

WARNING: The use of symlink link mode is discouraged, as they create tight coupling between
the cache and the target environment. For example, clearing the cache (`uv cache clean`)
will break all installed packages by way of removing the underlying source files. Use
symlinks with caution.

**Default value**: `"clone" (macOS) or "hardlink" (Linux, Windows)`

**Possible values**:

- `"clone"`: Clone (i.e., copy-on-write) packages from the wheel into the `site-packages` directory
- `"copy"`: Copy packages from the wheel into the `site-packages` directory
- `"hardlink"`: Hard link packages from the wheel into the `site-packages` directory
- `"symlink"`: Symbolically link packages from the wheel into the `site-packages` directory

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    link-mode = "copy"
    ```
=== "uv.toml"

    ```toml
    [pip]
    link-mode = "copy"
    ```

---

#### [`no-annotate`](#pip_no-annotate) {: #pip_no-annotate }
<span id="no-annotate"></span>

Exclude comment annotations indicating the source of each package from the output file
generated by `uv pip compile`.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-annotate = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-annotate = true
    ```

---

#### [`no-binary`](#pip_no-binary) {: #pip_no-binary }
<span id="no-binary"></span>

Don't install pre-built wheels.

The given packages will be built and installed from source. The resolver will still use
pre-built wheels to extract package metadata, if available.

Multiple packages may be provided. Disable binaries for all packages with `:all:`.
Clear previously specified packages with `:none:`.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-binary = ["ruff"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-binary = ["ruff"]
    ```

---

#### [`no-build`](#pip_no-build) {: #pip_no-build }
<span id="no-build"></span>

Don't build source distributions.

When enabled, resolving will not run arbitrary Python code. The cached wheels of
already-built source distributions will be reused, but operations that require building
distributions will exit with an error.

Alias for `--only-binary :all:`.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-build = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-build = true
    ```

---

#### [`no-build-isolation`](#pip_no-build-isolation) {: #pip_no-build-isolation }
<span id="no-build-isolation"></span>

Disable isolation when building source distributions.

Assumes that build dependencies specified by [PEP 518](https://peps.python.org/pep-0518/)
are already installed.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-build-isolation = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-build-isolation = true
    ```

---

#### [`no-build-isolation-package`](#pip_no-build-isolation-package) {: #pip_no-build-isolation-package }
<span id="no-build-isolation-package"></span>

Disable isolation when building source distributions for a specific package.

Assumes that the packages' build dependencies specified by [PEP 518](https://peps.python.org/pep-0518/)
are already installed.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-build-isolation-package = ["package1", "package2"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-build-isolation-package = ["package1", "package2"]
    ```

---

#### [`no-deps`](#pip_no-deps) {: #pip_no-deps }
<span id="no-deps"></span>

Ignore package dependencies, instead only add those packages explicitly listed
on the command line to the resulting requirements file.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-deps = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-deps = true
    ```

---

#### [`no-emit-package`](#pip_no-emit-package) {: #pip_no-emit-package }
<span id="no-emit-package"></span>

Specify a package to omit from the output resolution. Its dependencies will still be
included in the resolution. Equivalent to pip-compile's `--unsafe-package` option.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-emit-package = ["ruff"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-emit-package = ["ruff"]
    ```

---

#### [`no-extra`](#pip_no-extra) {: #pip_no-extra }
<span id="no-extra"></span>

Exclude the specified optional dependencies if `all-extras` is supplied.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    all-extras = true
    no-extra = ["dev", "docs"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    all-extras = true
    no-extra = ["dev", "docs"]
    ```

---

#### [`no-header`](#pip_no-header) {: #pip_no-header }
<span id="no-header"></span>

Exclude the comment header at the top of output file generated by `uv pip compile`.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-header = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-header = true
    ```

---

#### [`no-index`](#pip_no-index) {: #pip_no-index }
<span id="no-index"></span>

Ignore all registry indexes (e.g., PyPI), instead relying on direct URL dependencies and
those provided via `--find-links`.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-index = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-index = true
    ```

---

#### [`no-sources`](#pip_no-sources) {: #pip_no-sources }
<span id="no-sources"></span>

Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
standards-compliant, publishable package metadata, as opposed to using any local or Git
sources.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-sources = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-sources = true
    ```

---

#### [`no-strip-extras`](#pip_no-strip-extras) {: #pip_no-strip-extras }
<span id="no-strip-extras"></span>

Include extras in the output file.

By default, uv strips extras, as any packages pulled in by the extras are already included
as dependencies in the output file directly. Further, output files generated with
`--no-strip-extras` cannot be used as constraints files in `install` and `sync` invocations.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-strip-extras = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-strip-extras = true
    ```

---

#### [`no-strip-markers`](#pip_no-strip-markers) {: #pip_no-strip-markers }
<span id="no-strip-markers"></span>

Include environment markers in the output file generated by `uv pip compile`.

By default, uv strips environment markers, as the resolution generated by `compile` is
only guaranteed to be correct for the target environment.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    no-strip-markers = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    no-strip-markers = true
    ```

---

#### [`only-binary`](#pip_only-binary) {: #pip_only-binary }
<span id="only-binary"></span>

Only use pre-built wheels; don't build source distributions.

When enabled, resolving will not run code from the given packages. The cached wheels of already-built
source distributions will be reused, but operations that require building distributions will
exit with an error.

Multiple packages may be provided. Disable binaries for all packages with `:all:`.
Clear previously specified packages with `:none:`.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    only-binary = ["ruff"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    only-binary = ["ruff"]
    ```

---

#### [`output-file`](#pip_output-file) {: #pip_output-file }
<span id="output-file"></span>

Write the requirements generated by `uv pip compile` to the given `requirements.txt` file.

If the file already exists, the existing versions will be preferred when resolving
dependencies, unless `--upgrade` is also specified.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    output-file = "requirements.txt"
    ```
=== "uv.toml"

    ```toml
    [pip]
    output-file = "requirements.txt"
    ```

---

#### [`prefix`](#pip_prefix) {: #pip_prefix }
<span id="prefix"></span>

Install packages into `lib`, `bin`, and other top-level folders under the specified
directory, as if a virtual environment were present at that location.

In general, prefer the use of `--python` to install into an alternate environment, as
scripts and other artifacts installed via `--prefix` will reference the installing
interpreter, rather than any interpreter added to the `--prefix` directory, rendering them
non-portable.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    prefix = "./prefix"
    ```
=== "uv.toml"

    ```toml
    [pip]
    prefix = "./prefix"
    ```

---

#### [`prerelease`](#pip_prerelease) {: #pip_prerelease }
<span id="prerelease"></span>

The strategy to use when considering pre-release versions.

By default, uv will accept pre-releases for packages that _only_ publish pre-releases,
along with first-party requirements that contain an explicit pre-release marker in the
declared specifiers (`if-necessary-or-explicit`).

**Default value**: `"if-necessary-or-explicit"`

**Possible values**:

- `"disallow"`: Disallow all pre-release versions
- `"allow"`: Allow all pre-release versions
- `"if-necessary"`: Allow pre-release versions if all versions of a package are pre-release
- `"explicit"`: Allow pre-release versions for first-party packages with explicit pre-release markers in their version requirements
- `"if-necessary-or-explicit"`: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    prerelease = "allow"
    ```
=== "uv.toml"

    ```toml
    [pip]
    prerelease = "allow"
    ```

---

#### [`python`](#pip_python) {: #pip_python }
<span id="python"></span>

The Python interpreter into which packages should be installed.

By default, uv installs into the virtual environment in the current working directory or
any parent directory. The `--python` option allows you to specify a different interpreter,
which is intended for use in continuous integration (CI) environments or other automated
workflows.

Supported formats:
- `3.10` looks for an installed Python 3.10 in the registry on Windows (see
  `py --list-paths`), or `python3.10` on Linux and macOS.
- `python3.10` or `python.exe` looks for a binary with the given name in `PATH`.
- `/home/ferris/.local/bin/python3.10` uses the exact Python at the given path.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    python = "3.10"
    ```
=== "uv.toml"

    ```toml
    [pip]
    python = "3.10"
    ```

---

#### [`python-platform`](#pip_python-platform) {: #pip_python-platform }
<span id="python-platform"></span>

The platform for which requirements should be resolved.

Represented as a "target triple", a string that describes the target platform in terms of
its CPU, vendor, and operating system name, like `x86_64-unknown-linux-gnu` or
`aarch64-apple-darwin`.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    python-platform = "x86_64-unknown-linux-gnu"
    ```
=== "uv.toml"

    ```toml
    [pip]
    python-platform = "x86_64-unknown-linux-gnu"
    ```

---

#### [`python-version`](#pip_python-version) {: #pip_python-version }
<span id="python-version"></span>

The minimum Python version that should be supported by the resolved requirements (e.g.,
`3.8` or `3.8.17`).

If a patch version is omitted, the minimum patch version is assumed. For example, `3.8` is
mapped to `3.8.0`.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    python-version = "3.8"
    ```
=== "uv.toml"

    ```toml
    [pip]
    python-version = "3.8"
    ```

---

#### [`reinstall`](#pip_reinstall) {: #pip_reinstall }
<span id="reinstall"></span>

Reinstall all packages, regardless of whether they're already installed. Implies `refresh`.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    reinstall = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    reinstall = true
    ```

---

#### [`reinstall-package`](#pip_reinstall-package) {: #pip_reinstall-package }
<span id="reinstall-package"></span>

Reinstall a specific package, regardless of whether it's already installed. Implies
`refresh-package`.

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    reinstall-package = ["ruff"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    reinstall-package = ["ruff"]
    ```

---

#### [`require-hashes`](#pip_require-hashes) {: #pip_require-hashes }
<span id="require-hashes"></span>

Require a matching hash for each requirement.

Hash-checking mode is all or nothing. If enabled, _all_ requirements must be provided
with a corresponding hash or set of hashes. Additionally, if enabled, _all_ requirements
must either be pinned to exact versions (e.g., `==1.0.0`), or be specified via direct URL.

Hash-checking mode introduces a number of additional constraints:

- Git dependencies are not supported.
- Editable installations are not supported.
- Local dependencies are not supported, unless they point to a specific wheel (`.whl`) or
  source archive (`.zip`, `.tar.gz`), as opposed to a directory.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    require-hashes = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    require-hashes = true
    ```

---

#### [`resolution`](#pip_resolution) {: #pip_resolution }
<span id="resolution"></span>

The strategy to use when selecting between the different compatible versions for a given
package requirement.

By default, uv will use the latest compatible version of each package (`highest`).

**Default value**: `"highest"`

**Possible values**:

- `"highest"`: Resolve the highest compatible version of each package
- `"lowest"`: Resolve the lowest compatible version of each package
- `"lowest-direct"`: Resolve the lowest compatible version of any direct dependencies, and the highest compatible version of any transitive dependencies

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    resolution = "lowest-direct"
    ```
=== "uv.toml"

    ```toml
    [pip]
    resolution = "lowest-direct"
    ```

---

#### [`strict`](#pip_strict) {: #pip_strict }
<span id="strict"></span>

Validate the Python environment, to detect packages with missing dependencies and other
issues.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    strict = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    strict = true
    ```

---

#### [`system`](#pip_system) {: #pip_system }
<span id="system"></span>

Install packages into the system Python environment.

By default, uv installs into the virtual environment in the current working directory or
any parent directory. The `--system` option instructs uv to instead use the first Python
found in the system `PATH`.

WARNING: `--system` is intended for use in continuous integration (CI) environments and
should be used with caution, as it can modify the system Python installation.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    system = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    system = true
    ```

---

#### [`target`](#pip_target) {: #pip_target }
<span id="target"></span>

Install packages into the specified directory, rather than into the virtual or system Python
environment. The packages will be installed at the top-level of the directory.

**Default value**: `None`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    target = "./target"
    ```
=== "uv.toml"

    ```toml
    [pip]
    target = "./target"
    ```

---

#### [`torch-backend`](#pip_torch-backend) {: #pip_torch-backend }
<span id="torch-backend"></span>

The backend to use when fetching packages in the PyTorch ecosystem.

When set, uv will ignore the configured index URLs for packages in the PyTorch ecosystem,
and will instead use the defined backend.

For example, when set to `cpu`, uv will use the CPU-only PyTorch index; when set to `cu126`,
uv will use the PyTorch index for CUDA 12.6.

The `auto` mode will attempt to detect the appropriate PyTorch index based on the currently
installed CUDA drivers.

This option is in preview and may change in any future release.

**Default value**: `null`

**Type**: `str`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    torch-backend = "auto"
    ```
=== "uv.toml"

    ```toml
    [pip]
    torch-backend = "auto"
    ```

---

#### [`universal`](#pip_universal) {: #pip_universal }
<span id="universal"></span>

Perform a universal resolution, attempting to generate a single `requirements.txt` output
file that is compatible with all operating systems, architectures, and Python
implementations.

In universal mode, the current Python version (or user-provided `--python-version`) will be
treated as a lower bound. For example, `--universal --python-version 3.7` would produce a
universal resolution for Python 3.7 and later.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    universal = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    universal = true
    ```

---

#### [`upgrade`](#pip_upgrade) {: #pip_upgrade }
<span id="upgrade"></span>

Allow package upgrades, ignoring pinned versions in any existing output file.

**Default value**: `false`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    upgrade = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    upgrade = true
    ```

---

#### [`upgrade-package`](#pip_upgrade-package) {: #pip_upgrade-package }
<span id="upgrade-package"></span>

Allow upgrades for a specific package, ignoring pinned versions in any existing output
file.

Accepts both standalone package names (`ruff`) and version specifiers (`ruff<0.5.0`).

**Default value**: `[]`

**Type**: `list[str]`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    upgrade-package = ["ruff"]
    ```
=== "uv.toml"

    ```toml
    [pip]
    upgrade-package = ["ruff"]
    ```

---

#### [`verify-hashes`](#pip_verify-hashes) {: #pip_verify-hashes }
<span id="verify-hashes"></span>

Validate any hashes provided in the requirements file.

Unlike `--require-hashes`, `--verify-hashes` does not require that all requirements have
hashes; instead, it will limit itself to verifying the hashes of those requirements that do
include them.

**Default value**: `true`

**Type**: `bool`

**Example usage**:

=== "pyproject.toml"

    ```toml
    [tool.uv.pip]
    verify-hashes = true
    ```
=== "uv.toml"

    ```toml
    [pip]
    verify-hashes = true
    ```

---


    # Troubleshooting build failures

uv needs to build packages when there is not a compatible wheel (a pre-built distribution of the
package) available. Building packages can fail for many reasons, some of which may be unrelated to
uv itself.

## Recognizing a build failure

An example build failure can be produced by trying to install and old version of numpy on a new,
unsupported version of Python:

```console
$ uv pip install -p 3.13 'numpy<1.20'
Resolved 1 package in 62ms
  × Failed to build `numpy==1.19.5`
  ├─▶ The build backend returned an error
  ╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel()` failed (exit status: 1)

      [stderr]
      Traceback (most recent call last):
        File "<string>", line 8, in <module>
          from setuptools.build_meta import __legacy__ as backend
        File "/home/konsti/.cache/uv/builds-v0/.tmpi4bgKb/lib/python3.13/site-packages/setuptools/__init__.py", line 9, in <module>
          import distutils.core
      ModuleNotFoundError: No module named 'distutils'

      hint: `distutils` was removed from the standard library in Python 3.12. Consider adding a constraint (like `numpy >1.19.5`) to avoid building a version of `numpy` that depends
      on `distutils`.
```

Notice that the error message is prefaced by "The build backend returned an error".

The build failure includes the `[stderr]` (and `[stdout]`, if present) from the build backend that
was used for the build. The error logs are not from uv itself.

The message following the `╰─▶` is a hint provided by uv, to help resolve common build failures. A
hint will not be available for all build failures.

## Confirming that a build failure is specific to uv

Build failures are usually related to your system and the build backend. It is rare that a build
failure is specific to uv. You can confirm that the build failure is not related to uv by attempting
to reproduce it with pip:

```console
$ uv venv -p 3.13 --seed
$ source .venv/bin/activate
$ pip install --use-pep517 --no-cache --force-reinstall 'numpy==1.19.5'
Collecting numpy==1.19.5
  Using cached numpy-1.19.5.zip (7.3 MB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
ERROR: Exception:
Traceback (most recent call last):
  ...
  File "/Users/example/.cache/uv/archive-v0/3783IbOdglemN3ieOULx2/lib/python3.13/site-packages/pip/_vendor/pyproject_hooks/_impl.py", line 321, in _call_hook
    raise BackendUnavailable(data.get('traceback', ''))
pip._vendor.pyproject_hooks._impl.BackendUnavailable: Traceback (most recent call last):
  File "/Users/example/.cache/uv/archive-v0/3783IbOdglemN3ieOULx2/lib/python3.13/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 77, in _build_backend
    obj = import_module(mod_path)
  File "/Users/example/.local/share/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/importlib/__init__.py", line 88, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 1022, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/private/var/folders/6p/k5sd5z7j31b31pq4lhn0l8d80000gn/T/pip-build-env-vdpjme7d/overlay/lib/python3.13/site-packages/setuptools/__init__.py", line 9, in <module>
    import distutils.core
ModuleNotFoundError: No module named 'distutils'
```

!!! important

    The `--use-pep517` flag should be included with the `pip install` invocation to ensure the same
    build isolation behavior. uv always uses [build isolation by default](../../pip/compatibility.md#pep-517-build-isolation).

    We also recommend including the `--force-reinstall` and `--no-cache` options when reproducing
    failures.

Since this build failure occurs in pip too, it is not likely to be a bug with uv.

If a build failure is reproducible with another installer, you should investigate upstream (in this
example, `numpy` or `setuptools`), find a way to avoid building the package in the first place, or
make the necessary adjustments to your system for the build to succeed.

## Why does uv build a package?

When generating the cross-platform lockfile, uv needs to determine the dependencies of all packages,
even those only installed on other platforms. uv tries to avoid package builds during resolution. It
uses any wheel if exist for that version, then tries to find static metadata in the source
distribution (mainly pyproject.toml with static `project.version`, `project.dependencies` and
`project.optional-dependencies` or METADATA v2.2+). Only if all of that fails, it builds the
package.

When installing, uv needs to have a wheel for the current platform for each package. If no matching
wheel exists in the index, uv tries to build the source distribution.

You can check which wheels exist for a PyPI project under “Download Files”, e.g.
https://pypi.org/project/numpy/2.1.1.md#files. Wheels with `...-py3-none-any.whl` filenames work
everywhere, others have the operating system and platform in the filename. In the linked `numpy`
example, you can see that there are pre-built distributions for Python 3.10 to 3.13 on macOS, Linux
and Windows.

## Common build failures

The following examples demonstrate common build failures and how to resolve them.

### Command is not found

If the build error mentions a missing command, for example, `gcc`:

<!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.10-bookworm-slim /bin/bash -c "uv pip install --system pysha3==1.0.2" -->

```hl_lines="17"
× Failed to build `pysha3==1.0.2`
├─▶ The build backend returned an error
╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)

    [stdout]
    running bdist_wheel
    running build
    running build_py
    creating build/lib.linux-x86_64-cpython-310
    copying sha3.py -> build/lib.linux-x86_64-cpython-310
    running build_ext
    building '_pysha3' extension
    creating build/temp.linux-x86_64-cpython-310/Modules/_sha3
    gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DPY_WITH_KECCAK=1 -I/root/.cache/uv/builds-v0/.tmp8V4iEk/include -I/usr/local/include/python3.10 -c
    Modules/_sha3/sha3module.c -o build/temp.linux-x86_64-cpython-310/Modules/_sha3/sha3module.o

    [stderr]
    error: command 'gcc' failed: No such file or directory
```

Then, you'll need to install it with your system package manager, e.g., to resolve the error above:

```console
$ apt install gcc
```

!!! tip

    When using the uv-managed Python versions, it's common to need `clang` installed instead of
    `gcc`.

    Many Linux distributions provide a package that includes all the common build dependencies.
    You can address most build requirements by installing it, e.g., for Debian or Ubuntu:

    ```console
    $ apt install build-essential
    ```

### Header or library is missing

If the build error mentions a missing header or library, e.g., a `.h` file, then you'll need to
install it with your system package manager.

For example, installing `pygraphviz` requires Graphviz to be installed:

<!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.12-bookworm /bin/bash -c "uv pip install --system 'pygraphviz'" -->

```hl_lines="18-19"
× Failed to build `pygraphviz==1.14`
├─▶ The build backend returned an error
╰─▶ Call to `setuptools.build_meta.build_wheel` failed (exit status: 1)

  [stdout]
  running bdist_wheel
  running build
  running build_py
  ...
  gcc -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC -DSWIG_PYTHON_STRICT_BYTE_CHAR -I/root/.cache/uv/builds-v0/.tmpgLYPe0/include -I/usr/local/include/python3.12 -c pygraphviz/graphviz_wrap.c -o
  build/temp.linux-x86_64-cpython-312/pygraphviz/graphviz_wrap.o

  [stderr]
  ...
  pygraphviz/graphviz_wrap.c:9: warning: "SWIG_PYTHON_STRICT_BYTE_CHAR" redefined
      9 | #define SWIG_PYTHON_STRICT_BYTE_CHAR
        |
  <command-line>: note: this is the location of the previous definition
  pygraphviz/graphviz_wrap.c:3023:10: fatal error: graphviz/cgraph.h: No such file or directory
    3023 | #include "graphviz/cgraph.h"
        |          ^~~~~~~~~~~~~~~~~~~
  compilation terminated.
  error: command '/usr/bin/gcc' failed with exit code 1

  hint: This error likely indicates that you need to install a library that provides "graphviz/cgraph.h" for `pygraphviz@1.14`
```

To resolve this error on Debian, you'd install the `libgraphviz-dev` package:

```console
$ apt install libgraphviz-dev
```

Note that installing the `graphviz` package is not sufficient, the development headers need to be
installed.

!!! tip

    To resolve an error where `Python.h` is missing, install the [`python3-dev` package](https://packages.debian.org/bookworm/python3-dev).

### Module is missing or cannot be imported

If the build error mentions a failing import, consider
[disabling build isolation](../../concepts/projects/config.md#build-isolation).

For example, some packages assume that `pip` is available without declaring it as a build
dependency:

<!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.12-bookworm-slim /bin/bash -c "uv pip install --system chumpy" -->

```hl_lines="7"
  × Failed to build `chumpy==0.70`
  ├─▶ The build backend returned an error
  ╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)

    [stderr]
    Traceback (most recent call last):
      File "<string>", line 9, in <module>
    ModuleNotFoundError: No module named 'pip'

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
      File "<string>", line 14, in <module>
      File "/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py", line 334, in get_requires_for_build_wheel
        return self._get_build_requires(config_settings, requirements=[])
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py", line 304, in _get_build_requires
        self.run_setup()
      File "/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py", line 522, in run_setup
        super().run_setup(setup_script=setup_script)
      File "/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py", line 320, in run_setup
        exec(code, locals())
      File "<string>", line 11, in <module>
    ModuleNotFoundError: No module named 'pip'
```

To resolve this error, pre-install the build dependencies then disable build isolation for the
package:

```console
$ uv pip install pip setuptools
$ uv pip install chumpy --no-build-isolation-package chumpy
```

Note you will need to install the missing package, e.g., `pip`, _and_ all the other build
dependencies of the package, e.g, `setuptools`.

### Old version of the package is built

If a package fails to build during resolution and the version that failed to build is older than the
version you want to use, try adding a [constraint](../settings.md#constraint-dependencies) with a
lower bound (e.g., `numpy>=1.17`). Sometimes, due to algorithmic limitations, the uv resolver tries
to find a fitting version using unreasonably old packages, which can be prevented by using lower
bounds.

For example, when resolving the following dependencies on Python 3.10, uv attempts to build an old
version of `apache-beam`.

```title="requirements.txt"
dill<0.3.9,>=0.2.2
apache-beam<=2.49.0
```

<!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.10-bookworm-slim /bin/bash -c "printf 'dill<0.3.9,>=0.2.2\napache-beam<=2.49.0' | uv pip compile -" -->

```hl_lines="1"
× Failed to build `apache-beam==2.0.0`
├─▶ The build backend returned an error
╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)

    [stderr]
    ...
```

Adding a lower bound constraint, e.g., `apache-beam<=2.49.0,>2.30.0`, resolves this build failure as
uv will avoid using an old version of `apache-beam`.

Constraints can also be defined for indirect dependencies using `constraints.txt` files or the
[`constraint-dependencies`](../settings.md#constraint-dependencies) setting.

### Old Version of a build dependency is used

If a package fails to build because `uv` selects an incompatible or outdated version of a build-time
dependency, you can enforce constraints specifically for build dependencies. The
[`build-constraint-dependencies`](../settings.md#build-constraint-dependencies) setting (or an
analogous `build-constraints.txt` file) can be used to ensure that `uv` selects an appropriate
version of a given build requirements.

For example, the issue described in
[#5551](https://github.com/astral-sh/uv/issues/5551#issuecomment-2256055975) could be addressed by
specifying a build constraint that excludes `setuptools` version `72.0.0`:

```toml title="pyproject.toml"
[tool.uv]
# Prevent setuptools version 72.0.0 from being used as a build dependency.
build-constraint-dependencies = ["setuptools!=72.0.0"]
```

The build constraint will thus ensure that any package requiring `setuptools` during the build
process will avoid using the problematic version, preventing build failures caused by incompatible
build dependencies.

### Package is only needed for an unused platform

If locking fails due to building a package from a platform you do not need to support, consider
[limiting resolution](../../concepts/projects/config.md#limited-resolution-environments) to your
supported platforms.

### Package does not support all Python versions

If you support a large range of Python versions, consider using markers to use older versions for
older Python versions and newer versions for newer Python version. For example, `numpy` only
supports four Python minor version at a time, so to support a wider range of Python versions, e.g.,
Python 3.8 to 3.13, the `numpy` requirement needs to be split:

```
numpy>=1.23; python_version >= "3.10"
numpy<1.23; python_version < "3.10"
```

### Package is only usable on a specific platform

If locking fails due to building a package that is only usable on another platform, you can
[provide dependency metadata manually](../settings.md#dependency-metadata) to skip the build. uv can
not verify this information, so it is important to specify correct metadata when using this
override.

    # Troubleshooting

The troubleshooting section provides information about investigating failures in uv:

- [Build failures](./build-failures.md): Understanding common causes of package build failures.
- [Reproducible examples](./reproducible-examples.md): How to write a minimal reproducible example
  for a uv issue.

    # Reproducible examples

## Why reproducible examples are important

A minimal reproducible example (MRE) is essential for fixing bugs. Without an example that can be
used to reproduce the problem, a maintainer cannot debug it or test if it is fixed. If the example
is not minimal, i.e., if it includes lots of content which is not related to the issue, it can take
a maintainer much longer to identify the root cause of the problem.

## How to write a reproducible example

When writing a reproducible example, the goal is to provide all the context necessary for someone
else to reproduce your example. This includes:

- The platform you're using (e.g., the operating system and architecture)
- Any relevant system state (e.g., explicitly set environment variables)
- The version of uv
- The version of other relevant tools
- The relevant files (the `uv.lock`, `pyproject.toml`, etc.)
- The commands to run

To ensure your reproduction is minimal, remove as many dependencies, settings, and files as
possible. Be sure to test your reproduction before sharing it. We recommend including verbose logs
from your reproduction; they may differ on your machine in a critical way. Using a
[Gist](https://gist.github.com) can be helpful for very long logs.

Below, we'll cover several specific [strategies](#strategies-for-reproducible-examples) for creating
and sharing reproducible examples.

!!! tip

    There's a great guide to the basics of creating MREs on
    [Stack Overflow](https://stackoverflow.com/help/minimal-reproducible-example).

## Strategies for reproducible examples

### Docker image

Writing a Docker image is often the best way to share a reproducible example because it is entirely
self-contained. This means that the state from the reproducer's system does not affect the problem.

!!! note

    Using a Docker image is only feasible if the issue is reproducible on Linux. When using macOS,
    it's prudent to ensure your image is not reproducible on Linux but some bugs _are_ specific
    to the operating system. While using Docker to run Windows containers is feasible, it's not
    commonplace. These sorts of bugs are expected to be reported as a [script](#script) instead.

When writing a Docker MRE with uv, it's best to start with one of
[uv's Docker images](../../guides/integration/docker.md#available-images). When doing so, be sure to
pin to a specific version of uv.

```Dockerfile
FROM ghcr.io/astral-sh/uv:0.5.24-debian-slim
```

While Docker images are isolated from the system, the build will use your system's architecture by
default. When sharing a reproduction, you can explicitly set the platform to ensure a reproducer
gets the expected behavior. uv publishes images for `linux/amd64` (e.g., Intel or AMD) and
`linux/arm64` (e.g., Apple M Series or ARM)

```Dockerfile
FROM --platform=linux/amd64 ghcr.io/astral-sh/uv:0.5.24-debian-slim
```

Docker images are best for reproducing issues that can be constructed with commands, e.g.:

```Dockerfile
FROM --platform=linux/amd64 ghcr.io/astral-sh/uv:0.5.24-debian-slim

RUN uv init /mre
WORKDIR /mre
RUN uv add pydantic
RUN uv sync
RUN uv run -v python -c "import pydantic"
```

However, you can also write files into the image inline:

```Dockerfile
FROM --platform=linux/amd64 ghcr.io/astral-sh/uv:0.5.24-debian-slim

COPY <<EOF /mre/pyproject.toml
[project]
name = "example"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["pydantic"]
EOF

WORKDIR /mre
RUN uv lock
```

If you need to write many files, it's better to create and publish a
[Git repository](#git-repository). You can combine these approaches and include a `Dockerfile` in
the repository.

When sharing a Docker reproduction, it's helpful to include the build logs. You can see more output
from the build steps by disabling caching and the fancy output:

```console
docker build . --progress plain --no-cache
```

### Script

When reporting platform-specific bugs that cannot be reproduced in a [container](#docker-image),
it's best practice to include a script showing the commands that can be used to reproduce the bug,
e.g.:

```bash
uv init
uv add pydantic
uv sync
uv run -v python -c "import pydantic"
```

If your reproduction requires many files, use a [Git repository](#git-repository) to share them.

In addition to the script, include _verbose_ logs (i.e., with the `-v` flag) of the failure and the
complete error message.

Whenever a script relies on external state, be sure to share that information. For example, if you
wrote the script on Windows, and it uses a Python version that you installed with `choco` and runs
on PowerShell 6.2, please include that in the report.

### Git repository

When sharing a Git repository reproduction, include a [script](#script) that reproduces the problem
or, even better, a [Dockerfile](#docker-image). The first step of the script should be to clone the
repository and checkout a specific commit:

```console
$ git clone https://github.com/<user>/<project>.git
$ cd <project>
$ git checkout <commit>
$ <commands to produce error>
```

You can quickly create a new repository in the [GitHub UI](https://github.com/new) or with the `gh`
CLI:

```console
$ gh repo create uv-mre-1234 --clone
```

When using a Git repository for a reproduction, please remember to _minimize_ the contents by
excluding files or settings that are not required to reproduce your problem.