# Table of Contents - [Index | uv](#index-uv) - [Index | uv](#index-uv) - [Python versions | uv](#python-versions-uv) - [Caching | uv](#caching-uv) - [uv](#uv) - [Resolution | uv](#resolution-uv) - [Building distributions | uv](#building-distributions-uv) - [Configuring projects | uv](#configuring-projects-uv) - [Tools | uv](#tools-uv) - [Creating projects | uv](#creating-projects-uv) - [Managing dependencies | uv](#managing-dependencies-uv) - [Structure and files | uv](#structure-and-files-uv) - [Running commands | uv](#running-commands-uv) - [Locking and syncing | uv](#locking-and-syncing-uv) - [Using workspaces | uv](#using-workspaces-uv) - [Index | uv](#index-uv) - [Authentication | uv](#authentication-uv) - [Environment variables | uv](#environment-variables-uv) - [Installer | uv](#installer-uv) - [Package indexes | uv](#package-indexes-uv) - [Configuration files | uv](#configuration-files-uv) - [Index | uv](#index-uv) - [Features | uv](#features-uv) - [Getting help | uv](#getting-help-uv) - [First steps | uv](#first-steps-uv) - [Installation | uv](#installation-uv) - [Index | uv](#index-uv) - [Installing and managing Python | uv](#installing-and-managing-python-uv) - [Building and publishing a package | uv](#building-and-publishing-a-package-uv) - [Working on projects | uv](#working-on-projects-uv) - [Using alternative package indexes | uv](#using-alternative-package-indexes-uv) - [Using tools | uv](#using-tools-uv) - [Running scripts | uv](#running-scripts-uv) - [Index | uv](#index-uv) - [Using uv with FastAPI | uv](#using-uv-with-fastapi-uv) - [Using uv with dependency bots | uv](#using-uv-with-dependency-bots-uv) - [Using uv with AWS Lambda | uv](#using-uv-with-aws-lambda-uv) - [Using uv in GitHub Actions | uv](#using-uv-in-github-actions-uv) - [Using uv in Docker | uv](#using-uv-in-docker-uv) - [Using uv in GitLab CI/CD | uv](#using-uv-in-gitlab-ci-cd-uv) - [Using uv with Jupyter | uv](#using-uv-with-jupyter-uv) - [Using uv with pre-commit | uv](#using-uv-with-pre-commit-uv) - [Using uv with PyTorch | uv](#using-uv-with-pytorch-uv) - [Index | uv](#index-uv) - [Compatibility with pip | uv](#compatibility-with-pip-uv) - [Locking environments | uv](#locking-environments-uv) - [Declaring dependencies | uv](#declaring-dependencies-uv) - [Using environments | uv](#using-environments-uv) - [Inspecting packages | uv](#inspecting-packages-uv) - [Index | uv](#index-uv) - [Managing packages | uv](#managing-packages-uv) - [Benchmarks | uv](#benchmarks-uv) - [Resolver | uv](#resolver-uv) - [Index | uv](#index-uv) - [License | uv](#license-uv) - [Settings | uv](#settings-uv) - [Email Protection | Cloudflare](#email-protection-cloudflare) - [Build failures | uv](#build-failures-uv) - [Reproducible examples | uv](#reproducible-examples-uv) - [Commands | uv](#commands-uv) - [Platform support | uv](#platform-support-uv) - [Versioning | uv](#versioning-uv) - [Index | uv](#index-uv) --- # Index | uv [Concepts overview](#concepts-overview) ======================================== Read the concept documents to learn more about uv's features: * [Projects](projects/) * [Tools](tools/) * [Python versions](python-versions/) * [Resolution](resolution/) * [Caching](cache/) Looking for a quick introduction to features? See the [guides](../guides/) instead. Back to top --- # Index | uv [Projects](#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/) first. Working on projects is a core part of the uv experience. Learn more about using projects: * [Understanding project structure and files](layout/) * [Creating new projects](init/) * [Managing project dependencies](dependencies/) * [Running commands and scripts in a project](run/) * [Using lockfiles and syncing the environment](sync/) * [Configuring the project for advanced use cases](config/) * [Building distributions to publish a project](build/) * [Using workspaces to work on multiple projects at once](workspaces/) Back to top --- # Python versions | uv [Python versions](#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](#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](#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: `[](#__codelineno-0-1) $ 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: * `` (e.g., `3`, `3.12`, `3.12.3`) * `` (e.g., `>=3.12,<3.13`) * `` (e.g., `cpython` or `cp`) * `@` (e.g., `[[email protected]](/cdn-cgi/l/email-protection) `) * `` (e.g., `cpython3.12` or `cp312`) * `` (e.g., `cpython>=3.12,<3.13`) * `----` (e.g., `cpython-3.12.3-macos-aarch64-none`) Additionally, a specific system Python interpreter can be requested with: * `` (e.g., `/opt/homebrew/bin/python3`) * `` (e.g., `mypython3`) * `` (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](#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/#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/#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 (with the exception of the user configuration directory). [Installing a Python version](#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: `[](#__codelineno-1-1) $ uv python install 3.12.3` To install the latest patch version: `[](#__codelineno-2-1) $ uv python install 3.12` To install a version that satisfies constraints: `[](#__codelineno-3-1) $ uv python install '>=3.8,<3.10'` To install multiple versions: `[](#__codelineno-4-1) $ uv python install 3.9 3.10 3.11` To install a specific implementation: `[](#__codelineno-5-1) $ uv python install pypy` All of 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 of 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](#installing-python-executables) Important Support for installing Python executables is in _preview_, this means the behavior is experimental and subject to change. To install Python executables into your `PATH`, provide the `--preview` option: `[](#__codelineno-6-1) $ uv python install 3.12 --preview` This will install a Python executable for the requested version 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 `--default` option: `[](#__codelineno-7-1) $ uv python install 3.12 --default --preview` 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: ``[](#__codelineno-8-1) $ uv python install 3.12.7 --preview # Adds `python3.12` to `~/.local/bin` [](#__codelineno-8-2) $ uv python install 3.12.6 --preview # Does not update `python3.12` [](#__codelineno-8-3) $ uv python install 3.12.8 --preview # Updates `python3.12` to point to 3.12.8`` [Project Python versions](#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](#viewing-available-python-versions) ------------------------------------------------------------------------ To list installed and available Python versions: `[](#__codelineno-9-1) $ uv python list` To filter the Python versions, provide a request, e.g., to show all Python 3.13 interpreters: `[](#__codelineno-10-1) $ uv python list 3.13` Or, to show all PyPy interpreters: `[](#__codelineno-11-1) $ uv python list pypy` By default, downloads for other platforms and old patch versions are hidden. To view all versions: `[](#__codelineno-12-1) $ uv python list --all-versions` To view Python versions for other platforms: `[](#__codelineno-13-1) $ uv python list --all-platforms` To exclude downloads and only show installed Python versions: `[](#__codelineno-14-1) $ uv python list --only-installed` See the [`uv python list`](../../reference/cli/#uv-python-list) reference for more details. [Finding a Python executable](#finding-a-python-executable) ------------------------------------------------------------ To find a Python executable, use the `uv python find` command: `[](#__codelineno-15-1) $ 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: `[](#__codelineno-16-1) $ 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: `[](#__codelineno-17-1) $ uv python find --system` [Discovery of Python versions](#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/#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) 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. [Disabling automatic Python downloads](#disabling-automatic-python-downloads) ------------------------------------------------------------------------------ By default, uv will automatically download Python versions when needed. The [`python-downloads`](../../reference/settings/#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/) to change the default behavior, or the `--no-python-downloads` flag can be passed to any uv command. [Requiring or disabling managed Python versions](#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: `[](#__codelineno-18-1) $ uv python list --managed-python` Similarly, to ignore managed Python versions and only use system Python versions, use the `--no-managed-python` flag: `[](#__codelineno-19-1) $ 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](#adjusting-python-version-preferences) ------------------------------------------------------------------------------ The [`python-preference`](../../reference/settings/#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](#python-implementation-support) ---------------------------------------------------------------- uv supports the CPython, PyPy, 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` 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](#managed-python-distributions) -------------------------------------------------------------- uv supports downloading and installing CPython and PyPy distributions. ### [CPython 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; and, at present, uv does not support installing them on musl-based Linux distributions, like Alpine Linux. See the [`python-build-standalone` quirks](https://gregoryszorc.com/docs/python-build-standalone/main/quirks.html) documentation for details. ### [PyPy distributions](#pypy-distributions) PyPy distributions are provided by the PyPy project. Back to top --- # Caching | uv [Caching](#caching) ==================== [Dependency 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 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 flask` or `uv pip install --refresh-package flask ...`). * To force uv to ignore existing installed versions, pass `--reinstall` to any installation command (e.g., `uv sync --reinstall` or `uv pip install --reinstall ...`). 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](#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`: pyproject.toml `[](#__codelineno-0-1) [tool.uv] [](#__codelineno-0-2) 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: pyproject.toml `[](#__codelineno-1-1) [tool.uv] [](#__codelineno-1-2) 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`: pyproject.toml `[](#__codelineno-2-1) [tool.uv] [](#__codelineno-2-2) 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: pyproject.toml `[](#__codelineno-3-1) [tool.uv] [](#__codelineno-3-2) 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: pyproject.toml `[](#__codelineno-4-1) [tool.uv] [](#__codelineno-4-2) 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`: pyproject.toml `[](#__codelineno-5-1) [tool.uv] [](#__codelineno-5-2) 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: pyproject.toml `[](#__codelineno-6-1) [tool.uv] [](#__codelineno-6-2) 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](#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](#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](#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/#caching) . [Cache directory](#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/#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](#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. Back to top --- # uv [uv](#uv) ========== An extremely fast Python package and project manager, written in Rust. ![Shows a bar chart with benchmark results.](https://github.com/astral-sh/uv/assets/1309177/629e59c0-9c6e-4013-9ad4-adb2bcf5080d#only-light) ![Shows a bar chart with benchmark results.](https://github.com/astral-sh/uv/assets/1309177/03aa9163-1c79-4a87-a31d-7a9311ed9310#only-dark) _Installing [Trio](https://trio.readthedocs.io/) 's dependencies with a warm cache._ [Highlights](#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/#the-lockfile) . * ❇️ [Runs scripts](#scripts) , with support for [inline dependency metadata](guides/scripts/#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/) for scalable projects. * 💾 Disk-space efficient, with a [global cache](concepts/cache/) 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](#installation) ------------------------------ Install uv with our official standalone installer: macOS and LinuxWindows `[](#__codelineno-0-1) $ curl -LsSf https://astral.sh/uv/install.sh | sh` `[](#__codelineno-1-1) $ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"` Then, check out the [first steps](getting-started/first-steps/) 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/) . [Projects](#projects) ---------------------- uv manages project dependencies and environments, with support for lockfiles, workspaces, and more, similar to `rye` or `poetry`: ``[](#__codelineno-2-1) $ uv init example [](#__codelineno-2-2) Initialized project `example` at `/home/user/example` [](#__codelineno-2-3) [](#__codelineno-2-4) $ cd example [](#__codelineno-2-5) [](#__codelineno-2-6) $ uv add ruff [](#__codelineno-2-7) Creating virtual environment at: .venv [](#__codelineno-2-8) Resolved 2 packages in 170ms [](#__codelineno-2-9) Built example @ file:///home/user/example [](#__codelineno-2-10) Prepared 2 packages in 627ms [](#__codelineno-2-11) Installed 2 packages in 1ms [](#__codelineno-2-12) + example==0.1.0 (from file:///home/user/example) [](#__codelineno-2-13) + ruff==0.5.4 [](#__codelineno-2-14) [](#__codelineno-2-15) $ uv run ruff check [](#__codelineno-2-16) All checks passed! [](#__codelineno-2-17) [](#__codelineno-2-18) $ uv lock [](#__codelineno-2-19) Resolved 2 packages in 0.33ms [](#__codelineno-2-20) [](#__codelineno-2-21) $ uv sync [](#__codelineno-2-22) Resolved 2 packages in 0.70ms [](#__codelineno-2-23) Audited 1 package in 0.02ms`` See the [project guide](guides/projects/) to get started. uv also supports building and publishing projects, even if they're not managed with uv. See the [packaging guide](guides/package/) to learn more. [Scripts](#scripts) -------------------- uv manages dependencies and environments for single-file scripts. Create a new script and add inline metadata declaring its dependencies: `` [](#__codelineno-3-1) $ echo 'import requests; print(requests.get("https://astral.sh"))' > example.py [](#__codelineno-3-2) [](#__codelineno-3-3) $ uv add --script example.py requests [](#__codelineno-3-4) Updated `example.py` `` Then, run the script in an isolated virtual environment: `[](#__codelineno-4-1) $ uv run example.py [](#__codelineno-4-2) Reading inline script metadata from: example.py [](#__codelineno-4-3) Installed 5 packages in 12ms [](#__codelineno-4-4) ` See the [scripts guide](guides/scripts/) to get started. [Tools](#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`): `[](#__codelineno-5-1) $ uvx pycowsay 'hello world!' [](#__codelineno-5-2) Resolved 1 package in 167ms [](#__codelineno-5-3) Installed 1 package in 9ms [](#__codelineno-5-4) + pycowsay==0.0.0.2 [](#__codelineno-5-5) """ [](#__codelineno-5-6) [](#__codelineno-5-7) ------------ [](#__codelineno-5-8) < hello world! > [](#__codelineno-5-9) ------------ [](#__codelineno-5-10) \ ^__^ [](#__codelineno-5-11) \ (oo)\_______ [](#__codelineno-5-12) (__)\ )\/\ [](#__codelineno-5-13) ||----w | [](#__codelineno-5-14) || ||` Install a tool with `uv tool install`: `[](#__codelineno-6-1) $ uv tool install ruff [](#__codelineno-6-2) Resolved 1 package in 6ms [](#__codelineno-6-3) Installed 1 package in 2ms [](#__codelineno-6-4) + ruff==0.5.4 [](#__codelineno-6-5) Installed 1 executable: ruff [](#__codelineno-6-6) [](#__codelineno-6-7) $ ruff --version [](#__codelineno-6-8) ruff 0.5.4` See the [tools guide](guides/tools/) to get started. [Python versions](#python-versions) ------------------------------------ uv installs Python and allows quickly switching between versions. Install multiple Python versions: `[](#__codelineno-7-1) $ uv python install 3.10 3.11 3.12 [](#__codelineno-7-2) Searching for Python versions matching: Python 3.10 [](#__codelineno-7-3) Searching for Python versions matching: Python 3.11 [](#__codelineno-7-4) Searching for Python versions matching: Python 3.12 [](#__codelineno-7-5) Installed 3 versions in 3.42s [](#__codelineno-7-6) + cpython-3.10.14-macos-aarch64-none [](#__codelineno-7-7) + cpython-3.11.9-macos-aarch64-none [](#__codelineno-7-8) + cpython-3.12.4-macos-aarch64-none` Download Python versions as needed: `[](#__codelineno-8-1) $ uv venv --python 3.12.0 [](#__codelineno-8-2) Using CPython 3.12.0 [](#__codelineno-8-3) Creating virtual environment at: .venv [](#__codelineno-8-4) Activate with: source .venv/bin/activate [](#__codelineno-8-5) [](#__codelineno-8-6) $ uv run --python [[email protected]](/cdn-cgi/l/email-protection) -- python [](#__codelineno-8-7) Python 3.8.16 (a9dbdca6fc3286b0addd2240f11d97d8e8de187a, Dec 29 2022, 11:45:30) [](#__codelineno-8-8) [PyPy 7.3.11 with GCC Apple LLVM 13.1.6 (clang-1316.0.21.2.5)] on darwin [](#__codelineno-8-9) Type "help", "copyright", "credits" or "license" for more information. [](#__codelineno-8-10) >>>>` Use a specific Python version in the current directory: `` [](#__codelineno-9-1) $ uv python pin 3.11 [](#__codelineno-9-2) Pinned `.python-version` to `3.11` `` See the [installing Python guide](guides/install-python/) to get started. [The pip interface](#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: `[](#__codelineno-10-1) $ uv pip compile docs/requirements.in \ [](#__codelineno-10-2) --universal \ [](#__codelineno-10-3) --output-file docs/requirements.txt [](#__codelineno-10-4) Resolved 43 packages in 12ms` Create a virtual environment: `[](#__codelineno-11-1) $ uv venv [](#__codelineno-11-2) Using CPython 3.12.3 [](#__codelineno-11-3) Creating virtual environment at: .venv [](#__codelineno-11-4) Activate with: source .venv/bin/activate` Install the locked requirements: `[](#__codelineno-12-1) $ uv pip sync docs/requirements.txt [](#__codelineno-12-2) Resolved 43 packages in 11ms [](#__codelineno-12-3) Installed 43 packages in 208ms [](#__codelineno-12-4) + babel==2.15.0 [](#__codelineno-12-5) + black==24.4.2 [](#__codelineno-12-6) + certifi==2024.7.4 [](#__codelineno-12-7) ...` See the [pip interface documentation](pip/) to get started. [Learn more](#learn-more) -------------------------- See the [first steps](getting-started/first-steps/) or jump straight to the [guides](guides/) to start using uv. Back to top --- # Resolution | uv [Resolution](#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](#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](#basic-examples) ---------------------------------- To help demonstrate the resolution process, consider the following dependencies: * 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: * 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](#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](#platform-specific-resolution) -------------------------------------------------------------- By default, uv's pip interface, i.e., [`uv pip compile`](../../pip/compile/) , 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](#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](../projects/) 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/) , 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](#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: pyproject.toml `[](#__codelineno-0-1) [tool.uv] [](#__codelineno-0-2) environments = [ [](#__codelineno-0-3) "sys_platform == 'darwin'", [](#__codelineno-0-4) "sys_platform == 'linux'", [](#__codelineno-0-5) ]` Or, to avoid solving for alternative Python implementations: pyproject.toml `[](#__codelineno-1-1) [tool.uv] [](#__codelineno-1-2) environments = [ [](#__codelineno-1-3) "implementation_name == 'cpython'" [](#__codelineno-1-4) ]` 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](#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 Windows. 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: pyproject.toml `[](#__codelineno-2-1) [tool.uv] [](#__codelineno-2-2) required-environments = [ [](#__codelineno-2-3) "sys_platform == 'darwin' and platform_machine == 'x86_64'" [](#__codelineno-2-4) ]` [Dependency preferences](#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](#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: requirements.in `[](#__codelineno-3-1) flask>=2.0.0` Running `uv pip compile requirements.in` would produce the following `requirements.txt` file: requirements.txt `[](#__codelineno-4-1) # This file was autogenerated by uv via the following command: [](#__codelineno-4-2) # uv pip compile requirements.in [](#__codelineno-4-3) blinker==1.7.0 [](#__codelineno-4-4) # via flask [](#__codelineno-4-5) click==8.1.7 [](#__codelineno-4-6) # via flask [](#__codelineno-4-7) flask==3.0.0 [](#__codelineno-4-8) itsdangerous==2.1.2 [](#__codelineno-4-9) # via flask [](#__codelineno-4-10) jinja2==3.1.2 [](#__codelineno-4-11) # via flask [](#__codelineno-4-12) markupsafe==2.1.3 [](#__codelineno-4-13) # via [](#__codelineno-4-14) # jinja2 [](#__codelineno-4-15) # werkzeug [](#__codelineno-4-16) werkzeug==3.0.1 [](#__codelineno-4-17) # via flask` However, `uv pip compile --resolution lowest requirements.in` would instead produce: requirements.in `[](#__codelineno-5-1) # This file was autogenerated by uv via the following command: [](#__codelineno-5-2) # uv pip compile requirements.in --resolution lowest [](#__codelineno-5-3) click==7.1.2 [](#__codelineno-5-4) # via flask [](#__codelineno-5-5) flask==2.0.0 [](#__codelineno-5-6) itsdangerous==2.0.0 [](#__codelineno-5-7) # via flask [](#__codelineno-5-8) jinja2==3.0.0 [](#__codelineno-5-9) # via flask [](#__codelineno-5-10) markupsafe==2.0.0 [](#__codelineno-5-11) # via jinja2 [](#__codelineno-5-12) werkzeug==2.0.0 [](#__codelineno-5-13) # 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](#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`). 2. 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/#pre-release-compatibility) . [Multi-version resolution](#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: `[](#__codelineno-6-1) numpy==1.24.4 ; python_version == "3.8" [](#__codelineno-6-2) numpy==2.0.2 ; python_version == "3.9" [](#__codelineno-6-3) 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](#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) ---------------------------------------------- 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](#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`: `[](#__codelineno-7-1) [[tool.uv.dependency-metadata]] [](#__codelineno-7-2) name = "chumpy" [](#__codelineno-7-3) version = "0.70" [](#__codelineno-7-4) 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. 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, you can declare the metadata for `flash-attn`, allowing uv to resolve without building the package from source (which itself requires installing `torch`): `[](#__codelineno-8-1) [project] [](#__codelineno-8-2) name = "project" [](#__codelineno-8-3) version = "0.1.0" [](#__codelineno-8-4) requires-python = ">=3.12" [](#__codelineno-8-5) dependencies = ["flash-attn"] [](#__codelineno-8-6) [](#__codelineno-8-7) [tool.uv.sources] [](#__codelineno-8-8) flash-attn = { git = "https://github.com/Dao-AILab/flash-attention", tag = "v2.6.3" } [](#__codelineno-8-9) [](#__codelineno-8-10) [[tool.uv.dependency-metadata]] [](#__codelineno-8-11) name = "flash-attn" [](#__codelineno-8-12) version = "2.6.3" [](#__codelineno-8-13) 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. [Lower bounds](#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](#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](#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`) [Learn more](#learn-more) -------------------------- For more details about the internals of the resolver, see the [resolver reference](../../reference/resolver-internals/) documentation. [Lockfile versioning](#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/) ). 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. Back to top --- # Building distributions | uv [Building distributions](#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/#build-systems) . Information about build configuration can be found in the respective tool's documentation. [Using `uv build`](#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: `[](#__codelineno-0-1) $ uv build [](#__codelineno-0-2) $ ls dist/ [](#__codelineno-0-3) example-0.1.0-py3-none-any.whl [](#__codelineno-0-4) 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](#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`: `[](#__codelineno-1-1) 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: `[](#__codelineno-2-1) $ uv build --build-constraint constraints.txt --require-hashes` Back to top --- # Configuring projects | uv [Configuring projects](#configuring-projects) ============================================== [Python version requirement](#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: pyproject.toml `[](#__codelineno-0-1) [project] [](#__codelineno-0-2) name = "example" [](#__codelineno-0-3) version = "0.1.0" [](#__codelineno-0-4) 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) ------------------------------ [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](#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: pyproject.toml `[](#__codelineno-1-1) [project.scripts] [](#__codelineno-1-2) hello = "example:hello"` Then, the command can be run from a console: `[](#__codelineno-2-1) $ uv run hello` ### [Graphical user interfaces](#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: pyproject.toml `[](#__codelineno-3-1) [project.gui-scripts] [](#__codelineno-3-2) hello = "example:app"` ### [Plugin entry points](#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`: pyproject.toml `[](#__codelineno-4-1) [project.entry-points.'example.plugins'] [](#__codelineno-4-2) a = "example_plugin_a"` Then, in `example`, plugins would be loaded with: example/\_\_init\_\_.py `[](#__codelineno-5-1) from importlib.metadata import entry_points [](#__codelineno-5-2) [](#__codelineno-5-3) for plugin in entry_points(group='example.plugins'): [](#__codelineno-5-4) 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](#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 package or install it with `uv pip`, uv will always attempt to build and install it. ### [Build system options](#build-system-options) Build systems are used to power the following features: * Including or excluding files from distributions * Editable install 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](#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/#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. [Project environment path](#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`: `[](#__codelineno-6-1) $ python -c "import sysconfig; print(sysconfig.get_config_var('prefix'))" [](#__codelineno-6-2) /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. [Limited resolution environments](#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: pyproject.toml `[](#__codelineno-7-1) [tool.uv] [](#__codelineno-7-2) environments = [ [](#__codelineno-7-3) "sys_platform == 'darwin'", [](#__codelineno-7-4) "sys_platform == 'linux'", [](#__codelineno-7-5) ]` See the [resolution documentation](../../resolution/#limited-resolution-environments) for more. [Required environments](#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: pyproject.toml `[](#__codelineno-8-1) [tool.uv] [](#__codelineno-8-2) required-environments = [ [](#__codelineno-8-3) "sys_platform == 'darwin' and platform_machine == 'x86_64'", [](#__codelineno-8-4) ]` 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/#required-environments) for more. [Build isolation](#build-isolation) ------------------------------------ By default, uv builds all packages in isolated virtual environments, as per [PEP 517](https://peps.python.org/pep-0517/) . Some packages are incompatible with build isolation, be it intentionally (e.g., due to the use of heavy build dependencies, mostly commonly PyTorch) or unintentionally (e.g., due to the use of legacy packaging setups). To disable build isolation for a specific dependency, add it to the `no-build-isolation-package` list in your `pyproject.toml`: pyproject.toml `[](#__codelineno-9-1) [project] [](#__codelineno-9-2) name = "project" [](#__codelineno-9-3) version = "0.1.0" [](#__codelineno-9-4) description = "..." [](#__codelineno-9-5) readme = "README.md" [](#__codelineno-9-6) requires-python = ">=3.12" [](#__codelineno-9-7) dependencies = ["cchardet"] [](#__codelineno-9-8) [](#__codelineno-9-9) [tool.uv] [](#__codelineno-9-10) no-build-isolation-package = ["cchardet"]` Installing packages without build isolation requires that the package's build dependencies are installed in the project environment _prior_ to installing the package itself. This can be achieved by separating out the build dependencies and the packages that require them into distinct extras. For example: pyproject.toml `[](#__codelineno-10-1) [project] [](#__codelineno-10-2) name = "project" [](#__codelineno-10-3) version = "0.1.0" [](#__codelineno-10-4) description = "..." [](#__codelineno-10-5) readme = "README.md" [](#__codelineno-10-6) requires-python = ">=3.12" [](#__codelineno-10-7) dependencies = [] [](#__codelineno-10-8) [](#__codelineno-10-9) [project.optional-dependencies] [](#__codelineno-10-10) build = ["setuptools", "cython"] [](#__codelineno-10-11) compile = ["cchardet"] [](#__codelineno-10-12) [](#__codelineno-10-13) [tool.uv] [](#__codelineno-10-14) no-build-isolation-package = ["cchardet"]` Given the above, a user would first sync the `build` dependencies: `[](#__codelineno-11-1) $ uv sync --extra build [](#__codelineno-11-2) + cython==3.0.11 [](#__codelineno-11-3) + foo==0.1.0 (from file:///Users/crmarsh/workspace/uv/foo) [](#__codelineno-11-4) + setuptools==73.0.1` Followed by the `compile` dependencies: `[](#__codelineno-12-1) $ uv sync --extra compile [](#__codelineno-12-2) + cchardet==2.1.7 [](#__codelineno-12-3) - cython==3.0.11 [](#__codelineno-12-4) - setuptools==73.0.1` Note that `uv sync --extra compile` would, by default, uninstall the `cython` and `setuptools` packages. To instead retain the build dependencies, include both extras in the second `uv sync` invocation: `[](#__codelineno-13-1) $ uv sync --extra build [](#__codelineno-13-2) $ uv sync --extra build --extra compile` Some packages, like `cchardet` above, only require build dependencies for the _installation_ phase of `uv sync`. Others, like `flash-attn`, require their build dependencies to be present even just to resolve the project's lockfile during the _resolution_ phase. In such cases, the build dependencies must be installed prior to running any `uv lock` or `uv sync` commands, using the lower lower-level `uv pip` API. For example, given: pyproject.toml `[](#__codelineno-14-1) [project] [](#__codelineno-14-2) name = "project" [](#__codelineno-14-3) version = "0.1.0" [](#__codelineno-14-4) description = "..." [](#__codelineno-14-5) readme = "README.md" [](#__codelineno-14-6) requires-python = ">=3.12" [](#__codelineno-14-7) dependencies = ["flash-attn"] [](#__codelineno-14-8) [](#__codelineno-14-9) [tool.uv] [](#__codelineno-14-10) no-build-isolation-package = ["flash-attn"]` You could run the following sequence of commands to sync `flash-attn`: `[](#__codelineno-15-1) $ uv venv [](#__codelineno-15-2) $ uv pip install torch setuptools [](#__codelineno-15-3) $ uv sync` Alternatively, you can provide the `flash-attn` metadata upfront via the [`dependency-metadata`](../../../reference/settings/#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, include the following in your `pyproject.toml`: pyproject.toml `[](#__codelineno-16-1) [[tool.uv.dependency-metadata]] [](#__codelineno-16-2) name = "flash-attn" [](#__codelineno-16-3) version = "2.6.3" [](#__codelineno-16-4) 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.) Once included, you can again use the two-step `uv sync` process to install the build dependencies. Given the following `pyproject.toml`: pyproject.toml `[](#__codelineno-17-1) [project] [](#__codelineno-17-2) name = "project" [](#__codelineno-17-3) version = "0.1.0" [](#__codelineno-17-4) description = "..." [](#__codelineno-17-5) readme = "README.md" [](#__codelineno-17-6) requires-python = ">=3.12" [](#__codelineno-17-7) dependencies = [] [](#__codelineno-17-8) [](#__codelineno-17-9) [project.optional-dependencies] [](#__codelineno-17-10) build = ["torch", "setuptools", "packaging"] [](#__codelineno-17-11) compile = ["flash-attn"] [](#__codelineno-17-12) [](#__codelineno-17-13) [tool.uv] [](#__codelineno-17-14) no-build-isolation-package = ["flash-attn"] [](#__codelineno-17-15) [](#__codelineno-17-16) [[tool.uv.dependency-metadata]] [](#__codelineno-17-17) name = "flash-attn" [](#__codelineno-17-18) version = "2.6.3" [](#__codelineno-17-19) requires-dist = ["torch", "einops"]` You could run the following sequence of commands to sync `flash-attn`: `[](#__codelineno-18-1) $ uv sync --extra build [](#__codelineno-18-2) $ uv sync --extra build --extra compile` 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). [Editable mode](#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](#conflicting-dependencies) ------------------------------------------------------ uv requires that all optional dependencies ("extras") declared by the project are compatible with each other and resolves all optional dependencies together when creating the lockfile. If optional 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. To work around this, uv supports declaring conflicting extras. For example, consider two sets of optional dependencies that conflict with one another: pyproject.toml `[](#__codelineno-19-1) [project.optional-dependencies] [](#__codelineno-19-2) extra1 = ["numpy==2.1.2"] [](#__codelineno-19-3) extra2 = ["numpy==2.0.0"]` If you run `uv lock` with the above dependencies, resolution will fail: ``[](#__codelineno-20-1) $ uv lock [](#__codelineno-20-2) x No solution found when resolving dependencies: [](#__codelineno-20-3) `-> 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 [](#__codelineno-20-4) myproject[extra2] are incompatible. [](#__codelineno-20-5) And because your project requires myproject[extra1] and myproject[extra2], we can conclude that your projects's requirements are unsatisfiable.`` But if you specify that `extra1` and `extra2` are conflicting, uv will resolve them separately. Specify conflicts in the `tool.uv` section: pyproject.toml `[](#__codelineno-21-1) [tool.uv] [](#__codelineno-21-2) conflicts = [ [](#__codelineno-21-3) [ [](#__codelineno-21-4) { extra = "extra1" }, [](#__codelineno-21-5) { extra = "extra2" }, [](#__codelineno-21-6) ], [](#__codelineno-21-7) ]` Now, running `uv lock` will succeed. Note though, that now you cannot install both `extra1` and `extra2` at the same time: ``[](#__codelineno-22-1) $ uv sync --extra extra1 --extra extra2 [](#__codelineno-22-2) Resolved 3 packages in 14ms [](#__codelineno-22-3) 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 extras also works with dependency groups: pyproject.toml `[](#__codelineno-23-1) [dependency-groups] [](#__codelineno-23-2) group1 = ["numpy==2.1.2"] [](#__codelineno-23-3) group2 = ["numpy==2.0.0"] [](#__codelineno-23-4) [](#__codelineno-23-5) [tool.uv] [](#__codelineno-23-6) conflicts = [ [](#__codelineno-23-7) [ [](#__codelineno-23-8) { group = "group1" }, [](#__codelineno-23-9) { group = "group2" }, [](#__codelineno-23-10) ], [](#__codelineno-23-11) ]` The only difference with conflicting extras is that you need to use `group` instead of `extra`. Back to top --- # Tools | uv [Tools](#tools) ================ Tools are Python packages that provide command-line interfaces. Note See the [tools guide](../../guides/tools/) for an introduction to working with the tools interface — this document discusses details of tool management. [The `uv tool` interface](#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](#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](#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](#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: `[](#__codelineno-0-1) $ uvx [[email protected]](/cdn-cgi/l/email-protection) --version [](#__codelineno-0-2) ruff 0.6.0` A subsequent invocation of `uvx` will use the latest, not the cached, version. `[](#__codelineno-1-1) $ uvx ruff --version [](#__codelineno-1-2) 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: `[](#__codelineno-2-1) $ uvx ruff@latest --version [](#__codelineno-2-2) 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: `[](#__codelineno-3-1) $ uv tool install ruff==0.5.0` The version of `ruff` and `uvx ruff` is the same: `[](#__codelineno-4-1) $ ruff --version [](#__codelineno-4-2) ruff 0.5.0 [](#__codelineno-4-3) $ uvx ruff --version [](#__codelineno-4-4) ruff 0.5.0` However, you can ignore the installed version by requesting the latest version explicitly, e.g.: `[](#__codelineno-5-1) $ uvx ruff@latest --version [](#__codelineno-5-2) 0.6.2` Or, by using the `--isolated` flag, which will avoid refreshing the cache but ignore the installed version: `[](#__codelineno-6-1) $ uvx --isolated ruff --version [](#__codelineno-6-2) 0.6.2` `uv tool install` will also respect the `{package}@{version}` and `{package}@latest` specifiers, as in: `[](#__codelineno-7-1) $ uv tool install ruff@latest [](#__codelineno-7-2) $ uv tool install [[email protected]](/cdn-cgi/l/email-protection)` [Tools directory](#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: `[](#__codelineno-8-1) $ uv tool dir` Tool environments are placed in a directory with the same name as the tool package, e.g., `.../tools/`. 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](#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 `[](#__codelineno-9-1) $ uv tool upgrade black` To upgrade a single package in a tool environment: `[](#__codelineno-10-1) $ 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`: `[](#__codelineno-11-1) $ 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 `[](#__codelineno-12-1) $ uv tool upgrade black --reinstall` To reinstall a single package in a tool environment: `[](#__codelineno-13-1) $ uv tool upgrade black --reinstall-package click` [Including additional dependencies](#including-additional-dependencies) ------------------------------------------------------------------------ Additional packages can be included during tool execution: `[](#__codelineno-14-1) $ uvx --with ` And, during tool installation: `[](#__codelineno-15-1) $ uv tool install --with ` 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: `[](#__codelineno-16-1) $ uvx --with == ` If the requested version conflicts with the requirements of the tool package, package resolution will fail and the command will error. [Tool executables](#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](#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-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](#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`](#relationship-to-uv-run) ---------------------------------------------------- The invocation `uv tool run ` (or `uvx `) is nearly equivalent to: `[](#__codelineno-17-1) $ uv run --no-project --with -- ` 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`. Back to top --- # Creating projects | uv [Creating projects](#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](#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](#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. `[](#__codelineno-0-1) $ 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`). `[](#__codelineno-1-1) $ tree example-app [](#__codelineno-1-2) example-app [](#__codelineno-1-3) ├── .python-version [](#__codelineno-1-4) ├── README.md [](#__codelineno-1-5) ├── main.py [](#__codelineno-1-6) └── 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/#project-packaging) and will not be installed into the environment: pyproject.toml `[](#__codelineno-2-1) [project] [](#__codelineno-2-2) name = "example-app" [](#__codelineno-2-3) version = "0.1.0" [](#__codelineno-2-4) description = "Add your description here" [](#__codelineno-2-5) readme = "README.md" [](#__codelineno-2-6) requires-python = ">=3.11" [](#__codelineno-2-7) dependencies = []` The sample file defines a `main` function with some standard boilerplate: main.py `[](#__codelineno-3-1) def main(): [](#__codelineno-3-2) print("Hello from example-app!") [](#__codelineno-3-3) [](#__codelineno-3-4) [](#__codelineno-3-5) if __name__ == "__main__": [](#__codelineno-3-6) main()` Python files can be executed with `uv run`: `[](#__codelineno-4-1) $ cd example-app [](#__codelineno-4-2) $ uv run main.py [](#__codelineno-4-3) Hello from example-project!` [Packaged applications](#packaged-applications) ------------------------------------------------ Many use-cases require a [package](../config/#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: `[](#__codelineno-5-1) $ uv init --package example-pkg` The source code is moved into a `src` directory with a module directory and an `__init__.py` file: `[](#__codelineno-6-1) $ tree example-pkg [](#__codelineno-6-2) example-pkg [](#__codelineno-6-3) ├── .python-version [](#__codelineno-6-4) ├── README.md [](#__codelineno-6-5) ├── pyproject.toml [](#__codelineno-6-6) └── src [](#__codelineno-6-7) └── example_pkg [](#__codelineno-6-8) └── __init__.py` A [build system](../config/#build-systems) is defined, so the project will be installed into the environment: pyproject.toml `[](#__codelineno-7-1) [project] [](#__codelineno-7-2) name = "example-pkg" [](#__codelineno-7-3) version = "0.1.0" [](#__codelineno-7-4) description = "Add your description here" [](#__codelineno-7-5) readme = "README.md" [](#__codelineno-7-6) requires-python = ">=3.11" [](#__codelineno-7-7) dependencies = [] [](#__codelineno-7-8) [](#__codelineno-7-9) [project.scripts] [](#__codelineno-7-10) example-pkg = "example_pkg:main" [](#__codelineno-7-11) [](#__codelineno-7-12) [build-system] [](#__codelineno-7-13) requires = ["hatchling"] [](#__codelineno-7-14) build-backend = "hatchling.build"` Tip The `--build-backend` option can be used to request an alternative build system. A [command](../config/#entry-points) definition is included: pyproject.toml `[](#__codelineno-8-1) [project] [](#__codelineno-8-2) name = "example-pkg" [](#__codelineno-8-3) version = "0.1.0" [](#__codelineno-8-4) description = "Add your description here" [](#__codelineno-8-5) readme = "README.md" [](#__codelineno-8-6) requires-python = ">=3.11" [](#__codelineno-8-7) dependencies = [] [](#__codelineno-8-8) [](#__codelineno-8-9) [project.scripts] [](#__codelineno-8-10) example-pkg = "example_pkg:main" [](#__codelineno-8-11) [](#__codelineno-8-12) [build-system] [](#__codelineno-8-13) requires = ["hatchling"] [](#__codelineno-8-14) build-backend = "hatchling.build"` The command can be executed with `uv run`: `[](#__codelineno-9-1) $ cd example-pkg [](#__codelineno-9-2) $ uv run example-pkg [](#__codelineno-9-3) Hello from example-pkg!` [Libraries](#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: `[](#__codelineno-10-1) $ 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: `[](#__codelineno-11-1) $ tree example-lib [](#__codelineno-11-2) example-lib [](#__codelineno-11-3) ├── .python-version [](#__codelineno-11-4) ├── README.md [](#__codelineno-11-5) ├── pyproject.toml [](#__codelineno-11-6) └── src [](#__codelineno-11-7) └── example_lib [](#__codelineno-11-8) ├── py.typed [](#__codelineno-11-9) └── __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/#build-systems) is defined, so the project will be installed into the environment: pyproject.toml `[](#__codelineno-12-1) [project] [](#__codelineno-12-2) name = "example-lib" [](#__codelineno-12-3) version = "0.1.0" [](#__codelineno-12-4) description = "Add your description here" [](#__codelineno-12-5) readme = "README.md" [](#__codelineno-12-6) requires-python = ">=3.11" [](#__codelineno-12-7) dependencies = [] [](#__codelineno-12-8) [](#__codelineno-12-9) [build-system] [](#__codelineno-12-10) requires = ["hatchling"] [](#__codelineno-12-11) build-backend = "hatchling.build"` Tip You can select a different build backend template by using `--build-backend` with `hatchling`, `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: \_\_init\_\_.py `[](#__codelineno-13-1) def hello() -> str: [](#__codelineno-13-2) return "Hello from example-lib!"` And you can import and execute it using `uv run`: `[](#__codelineno-14-1) $ cd example-lib [](#__codelineno-14-2) $ uv run python -c "import example_lib; print(example_lib.hello())" [](#__codelineno-14-3) Hello from example-lib!` [Projects with extension modules](#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: `[](#__codelineno-15-1) $ 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: `[](#__codelineno-16-1) $ tree example-ext [](#__codelineno-16-2) example-ext [](#__codelineno-16-3) ├── .python-version [](#__codelineno-16-4) ├── Cargo.toml [](#__codelineno-16-5) ├── README.md [](#__codelineno-16-6) ├── pyproject.toml [](#__codelineno-16-7) └── src [](#__codelineno-16-8) ├── lib.rs [](#__codelineno-16-9) └── example_ext [](#__codelineno-16-10) ├── __init__.py [](#__codelineno-16-11) └── _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: src/lib.rs `[](#__codelineno-17-1) use pyo3::prelude::*; [](#__codelineno-17-2) [](#__codelineno-17-3) #[pyfunction] [](#__codelineno-17-4) fn hello_from_bin() -> String { [](#__codelineno-17-5) "Hello from example-ext!".to_string() [](#__codelineno-17-6) } [](#__codelineno-17-7) [](#__codelineno-17-8) #[pymodule] [](#__codelineno-17-9) fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> { [](#__codelineno-17-10) m.add_function(wrap_pyfunction!(hello_from_bin, m)?)?; [](#__codelineno-17-11) Ok(()) [](#__codelineno-17-12) }` And the Python module imports it: src/example\_ext/\_\_init\_\_.py `[](#__codelineno-18-1) from example_ext._core import hello_from_bin [](#__codelineno-18-2) [](#__codelineno-18-3) [](#__codelineno-18-4) def main() -> None: [](#__codelineno-18-5) print(hello_from_bin())` The command can be executed with `uv run`: `[](#__codelineno-19-1) $ cd example-ext [](#__codelineno-19-2) $ uv run example-ext [](#__codelineno-19-3) Hello from example-ext!` Important Changes to the extension code in `lib.rs` or `main.cpp` will require running `--reinstall` to rebuild them. [Creating a minimal project](#creating-a-minimal-project) ---------------------------------------------------------- If you only want to create a `pyproject.toml`, use the `--bare` option: `[](#__codelineno-20-1) $ 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`). `[](#__codelineno-21-1) $ tree example-bare [](#__codelineno-21-2) example-bare [](#__codelineno-21-3) └── pyproject.toml` uv will also not add extra metadata to the `pyproject.toml`, such as the `description` or `authors`. `[](#__codelineno-22-1) [project] [](#__codelineno-22-2) name = "example" [](#__codelineno-22-3) version = "0.1.0" [](#__codelineno-22-4) requires-python = ">=3.12" [](#__codelineno-22-5) 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: `[](#__codelineno-23-1) $ uv init example --bare --description "Hello world" --author-from git --vcs git --python-pin` Back to top --- # Managing dependencies | uv [Managing dependencies](#managing-dependencies) ================================================ [Dependency fields](#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](#adding-dependencies) -------------------------------------------- To add a dependency: `[](#__codelineno-0-1) $ uv add httpx` An entry will be added in the `project.dependencies` field: pyproject.toml `[](#__codelineno-1-1) [project] [](#__codelineno-1-2) name = "example" [](#__codelineno-1-3) version = "0.1.0" [](#__codelineno-1-4) dependencies = ["httpx>=0.27.2"]` The [`--dev`](#development-dependencies) , [`--group`](#dependency-groups) , or [`--optional`](#optional-dependencies) flags can be used to add a 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. An alternative constraint can be provided: `[](#__codelineno-2-1) $ 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: `[](#__codelineno-3-1) $ uv add "httpx @ git+https://github.com/encode/httpx"` The `pyproject.toml` will include a [Git source entry](#git) : pyproject.toml `[](#__codelineno-4-1) [project] [](#__codelineno-4-2) name = "example" [](#__codelineno-4-3) version = "0.1.0" [](#__codelineno-4-4) dependencies = [ [](#__codelineno-4-5) "httpx", [](#__codelineno-4-6) ] [](#__codelineno-4-7) [](#__codelineno-4-8) [tool.uv.sources] [](#__codelineno-4-9) httpx = { git = "https://github.com/encode/httpx" }` If a dependency cannot be used, uv will display an error.: `[](#__codelineno-5-1) $ uv add "httpx>9999" [](#__codelineno-5-2) × No solution found when resolving dependencies: [](#__codelineno-5-3) ╰─▶ Because only httpx<=1.0.0b0 is available and your project depends on httpx>9999, [](#__codelineno-5-4) we can conclude that your project's requirements are unsatisfiable.` ### [Importing dependencies](#importing-dependencies) Dependencies declared in a `requirements.txt` file can be added to the project with the `-r` option: `[](#__codelineno-6-1) uv add -r requirements.txt` [Removing dependencies](#removing-dependencies) ------------------------------------------------ To remove a dependency: `[](#__codelineno-7-1) $ 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](#changing-dependencies) ------------------------------------------------ To change an existing dependency, e.g., to use a different constraint for `httpx`: `[](#__codelineno-8-1) $ 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 `, e.g.: `[](#__codelineno-9-1) $ uv add "httpx>0.1.0" --upgrade-package httpx` See the [lockfile](../sync/#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: `[](#__codelineno-10-1) $ uv add "httpx @ ../httpx"` [Platform-specific dependencies](#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: `[](#__codelineno-11-1) $ uv add "jax; sys_platform == 'linux'"` The resulting `pyproject.toml` will then include the environment marker in the dependency definition: pyproject.toml `[](#__codelineno-12-1) [project] [](#__codelineno-12-2) name = "project" [](#__codelineno-12-3) version = "0.1.0" [](#__codelineno-12-4) requires-python = ">=3.11" [](#__codelineno-12-5) dependencies = ["jax; sys_platform == 'linux'"]` Similarly, to include `numpy` on Python 3.11 and later: `[](#__codelineno-13-1) $ 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](#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: pyproject.toml `[](#__codelineno-14-1) [project] [](#__codelineno-14-2) name = "albatross" [](#__codelineno-14-3) version = "0.1.0" [](#__codelineno-14-4) dependencies = [ [](#__codelineno-14-5) # Any version in this range [](#__codelineno-14-6) "tqdm >=4.66.2,<5", [](#__codelineno-14-7) # Exactly this version of torch [](#__codelineno-14-8) "torch ==2.2.2", [](#__codelineno-14-9) # Install transformers with the torch extra [](#__codelineno-14-10) "transformers[torch] >=4.39.3,<5", [](#__codelineno-14-11) # Only install this package on older python versions [](#__codelineno-14-12) # See "Environment Markers" for more information [](#__codelineno-14-13) "importlib_metadata >=7.1.0,<8; python_version < '3.10'", [](#__codelineno-14-14) "mollymawk ==0.1.0" [](#__codelineno-14-15) ]` [Dependency sources](#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 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: pyproject.toml `[](#__codelineno-15-1) [project] [](#__codelineno-15-2) name = "example" [](#__codelineno-15-3) version = "0.1.0" [](#__codelineno-15-4) dependencies = ["foo"] [](#__codelineno-15-5) [](#__codelineno-15-6) [tool.uv.sources] [](#__codelineno-15-7) 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](#index) To add Python package from a specific index, use the `--index` option: `[](#__codelineno-16-1) $ 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: pyproject.toml `[](#__codelineno-17-1) [project] [](#__codelineno-17-2) dependencies = ["torch"] [](#__codelineno-17-3) [](#__codelineno-17-4) [tool.uv.sources] [](#__codelineno-17-5) torch = { index = "pytorch" } [](#__codelineno-17-6) [](#__codelineno-17-7) [[tool.uv.index]] [](#__codelineno-17-8) name = "pytorch" [](#__codelineno-17-9) 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/) 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. pyproject.toml `[](#__codelineno-18-1) [[tool.uv.index]] [](#__codelineno-18-2) name = "pytorch" [](#__codelineno-18-3) url = "https://download.pytorch.org/whl/cpu" [](#__codelineno-18-4) explicit = true` ### [Git](#git) To add a Git dependency source, prefix a Git-compatible URL (i.e., that you would use with `git clone`) with `git+`. For example: `[](#__codelineno-19-1) $ uv add git+https://github.com/encode/httpx` pyproject.toml `[](#__codelineno-20-1) [project] [](#__codelineno-20-2) dependencies = ["httpx"] [](#__codelineno-20-3) [](#__codelineno-20-4) [tool.uv.sources] [](#__codelineno-20-5) httpx = { git = "https://github.com/encode/httpx" }` Specific Git references can be requested, e.g., a tag: `[](#__codelineno-21-1) $ uv add git+https://github.com/encode/httpx --tag 0.27.0` pyproject.toml `[](#__codelineno-22-1) [project] [](#__codelineno-22-2) dependencies = ["httpx"] [](#__codelineno-22-3) [](#__codelineno-22-4) [tool.uv.sources] [](#__codelineno-22-5) httpx = { git = "https://github.com/encode/httpx", tag = "0.27.0" }` Or, a branch: `[](#__codelineno-23-1) $ uv add git+https://github.com/encode/httpx --branch main` pyproject.toml `[](#__codelineno-24-1) [project] [](#__codelineno-24-2) dependencies = ["httpx"] [](#__codelineno-24-3) [](#__codelineno-24-4) [tool.uv.sources] [](#__codelineno-24-5) httpx = { git = "https://github.com/encode/httpx", branch = "main" }` Or, a revision (commit): `[](#__codelineno-25-1) $ uv add git+https://github.com/encode/httpx --rev 326b9431c761e1ef1e00b9f760d1f654c8db48c6` pyproject.toml `[](#__codelineno-26-1) [project] [](#__codelineno-26-2) dependencies = ["httpx"] [](#__codelineno-26-3) [](#__codelineno-26-4) [tool.uv.sources] [](#__codelineno-26-5) httpx = { git = "https://github.com/encode/httpx", rev = "326b9431c761e1ef1e00b9f760d1f654c8db48c6" }` A `subdirectory` may be specified if the package isn't in the repository root: `[](#__codelineno-27-1) $ uv add git+https://github.com/langchain-ai/langchain#subdirectory=libs/langchain` pyproject.toml `[](#__codelineno-28-1) [project] [](#__codelineno-28-2) dependencies = ["langchain"] [](#__codelineno-28-3) [](#__codelineno-28-4) [tool.uv.sources] [](#__codelineno-28-5) langchain = { git = "https://github.com/langchain-ai/langchain", subdirectory = "libs/langchain" }` ### [URL](#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](../../resolution/#source-distribution) for all supported formats). For example: `[](#__codelineno-29-1) $ uv add "https://files.pythonhosted.org/packages/5c/2d/3da5bdf4408b8b2800061c339f240c1802f2e82d55e50bd39c5a881f47f0/httpx-0.27.0.tar.gz"` Will result in a `pyproject.toml` with: pyproject.toml `[](#__codelineno-30-1) [project] [](#__codelineno-30-2) dependencies = ["httpx"] [](#__codelineno-30-3) [](#__codelineno-30-4) [tool.uv.sources] [](#__codelineno-30-5) 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 = }` syntax. A `subdirectory` may be specified if the source distribution isn't in the archive root. ### [Path](#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](../../resolution/#source-distribution) for all supported formats), or a directory containing a `pyproject.toml`. For example: `[](#__codelineno-31-1) $ uv add /example/foo-0.1.0-py3-none-any.whl` Will result in a `pyproject.toml` with: pyproject.toml `[](#__codelineno-32-1) [project] [](#__codelineno-32-2) dependencies = ["foo"] [](#__codelineno-32-3) [](#__codelineno-32-4) [tool.uv.sources] [](#__codelineno-32-5) foo = { path = "/example/foo-0.1.0-py3-none-any.whl" }` The path may also be a relative path: `[](#__codelineno-33-1) $ uv add ./foo-0.1.0-py3-none-any.whl` Or, a path to a project directory: `[](#__codelineno-34-1) $ uv add ~/projects/bar/` Important An [editable installation](#editable-dependencies) is not used for path dependencies by default. An editable installation may be requested for project directories: `[](#__codelineno-35-1) $ uv add --editable ../projects/bar/` Which will result in a `pyproject.toml` with: pyproject.toml `[](#__codelineno-36-1) [project] [](#__codelineno-36-2) dependencies = ["bar"] [](#__codelineno-36-3) [](#__codelineno-36-4) [tool.uv.sources] [](#__codelineno-36-5) bar = { path = "../projects/bar", editable = true }` Similarly, if a project is marked as a [non-package](../config/#build-systems) , but you'd like to install it in the environment as a package, set `package = true` on the source: pyproject.toml `[](#__codelineno-37-1) [project] [](#__codelineno-37-2) dependencies = ["bar"] [](#__codelineno-37-3) [](#__codelineno-37-4) [tool.uv.sources] [](#__codelineno-37-5) bar = { path = "../projects/bar", package = true }` For multiple packages in the same repository, [_workspaces_](../workspaces/) may be a better fit. ### [Workspace member](#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/) documentation for more details on workspaces. pyproject.toml `[](#__codelineno-38-1) [project] [](#__codelineno-38-2) dependencies = ["foo==0.1.0"] [](#__codelineno-38-3) [](#__codelineno-38-4) [tool.uv.sources] [](#__codelineno-38-5) foo = { workspace = true } [](#__codelineno-38-6) [](#__codelineno-38-7) [tool.uv.workspace] [](#__codelineno-38-8) members = [ [](#__codelineno-38-9) "packages/foo" [](#__codelineno-38-10) ]` ### [Platform-specific sources](#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: pyproject.toml `[](#__codelineno-39-1) [project] [](#__codelineno-39-2) dependencies = ["httpx"] [](#__codelineno-39-3) [](#__codelineno-39-4) [tool.uv.sources] [](#__codelineno-39-5) 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](#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: pyproject.toml `[](#__codelineno-40-1) [project] [](#__codelineno-40-2) dependencies = ["httpx"] [](#__codelineno-40-3) [](#__codelineno-40-4) [tool.uv.sources] [](#__codelineno-40-5) httpx = [ [](#__codelineno-40-6) { git = "https://github.com/encode/httpx", tag = "0.27.2", marker = "sys_platform == 'darwin'" }, [](#__codelineno-40-7) { git = "https://github.com/encode/httpx", tag = "0.24.1", marker = "sys_platform == 'linux'" }, [](#__codelineno-40-8) ]` This strategy extends to using different indexes based on environment markers. For example, to install `torch` from different PyTorch indexes based on the platform: pyproject.toml `[](#__codelineno-41-1) [project] [](#__codelineno-41-2) dependencies = ["torch"] [](#__codelineno-41-3) [](#__codelineno-41-4) [tool.uv.sources] [](#__codelineno-41-5) torch = [ [](#__codelineno-41-6) { index = "torch-cpu", marker = "platform_system == 'Darwin'"}, [](#__codelineno-41-7) { index = "torch-gpu", marker = "platform_system == 'Linux'"}, [](#__codelineno-41-8) ] [](#__codelineno-41-9) [](#__codelineno-41-10) [[tool.uv.index]] [](#__codelineno-41-11) name = "torch-cpu" [](#__codelineno-41-12) url = "https://download.pytorch.org/whl/cpu" [](#__codelineno-41-13) [](#__codelineno-41-14) [[tool.uv.index]] [](#__codelineno-41-15) name = "torch-gpu" [](#__codelineno-41-16) url = "https://download.pytorch.org/whl/cu124"` ### [Disabling sources](#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: `[](#__codelineno-42-1) $ 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](#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[]` 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-pep-508) syntax. Optional dependencies can have entries in `tool.uv.sources` the same as normal dependencies. pyproject.toml `[](#__codelineno-43-1) [project] [](#__codelineno-43-2) name = "pandas" [](#__codelineno-43-3) version = "1.0.0" [](#__codelineno-43-4) [](#__codelineno-43-5) [project.optional-dependencies] [](#__codelineno-43-6) plot = [ [](#__codelineno-43-7) "matplotlib>=3.6.3" [](#__codelineno-43-8) ] [](#__codelineno-43-9) excel = [ [](#__codelineno-43-10) "odfpy>=1.4.1", [](#__codelineno-43-11) "openpyxl>=3.1.0", [](#__codelineno-43-12) "python-calamine>=0.1.7", [](#__codelineno-43-13) "pyxlsb>=1.0.10", [](#__codelineno-43-14) "xlrd>=2.0.1", [](#__codelineno-43-15) "xlsxwriter>=3.0.5" [](#__codelineno-43-16) ]` To add an optional dependency, use the `--optional ` option: `[](#__codelineno-44-1) $ 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/#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: pyproject.toml `[](#__codelineno-45-1) [project] [](#__codelineno-45-2) dependencies = [] [](#__codelineno-45-3) [](#__codelineno-45-4) [project.optional-dependencies] [](#__codelineno-45-5) cpu = [ [](#__codelineno-45-6) "torch", [](#__codelineno-45-7) ] [](#__codelineno-45-8) gpu = [ [](#__codelineno-45-9) "torch", [](#__codelineno-45-10) ] [](#__codelineno-45-11) [](#__codelineno-45-12) [tool.uv.sources] [](#__codelineno-45-13) torch = [ [](#__codelineno-45-14) { index = "torch-cpu", extra = "cpu" }, [](#__codelineno-45-15) { index = "torch-gpu", extra = "gpu" }, [](#__codelineno-45-16) ] [](#__codelineno-45-17) [](#__codelineno-45-18) [[tool.uv.index]] [](#__codelineno-45-19) name = "torch-cpu" [](#__codelineno-45-20) url = "https://download.pytorch.org/whl/cpu" [](#__codelineno-45-21) [](#__codelineno-45-22) [[tool.uv.index]] [](#__codelineno-45-23) name = "torch-gpu" [](#__codelineno-45-24) url = "https://download.pytorch.org/whl/cu124"` [Development dependencies](#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: `[](#__codelineno-46-1) $ 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: pyproject.toml `[](#__codelineno-47-1) [dependency-groups] [](#__codelineno-47-2) dev = [ [](#__codelineno-47-3) "pytest >=8.1.1,<9" [](#__codelineno-47-4) ]` 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](#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: `[](#__codelineno-48-1) $ uv add --group lint ruff` Which results in the following `[dependency-groups]` definition: pyproject.toml `[](#__codelineno-49-1) [dependency-groups] [](#__codelineno-49-2) dev = [ [](#__codelineno-49-3) "pytest" [](#__codelineno-49-4) ] [](#__codelineno-49-5) lint = [ [](#__codelineno-49-6) "ruff" [](#__codelineno-49-7) ]` 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/#conflicting-dependencies) . ### [Default groups](#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. pyproject.toml `[](#__codelineno-50-1) [tool.uv] [](#__codelineno-50-2) default-groups = ["dev", "foo"]` To enable all dependencies groups by default, use `"all"` instead of listing group names: pyproject.toml `[](#__codelineno-51-1) [tool.uv] [](#__codelineno-51-2) 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 `. ### [Legacy `dev-dependencies`](#legacy-dev-dependencies) Before `[dependency-groups]` was standardized, uv used the `tool.uv.dev-dependencies` field to specify development dependencies, e.g.: pyproject.toml `[](#__codelineno-52-1) [tool.uv] [](#__codelineno-52-2) dev-dependencies = [ [](#__codelineno-52-3) "pytest" [](#__codelineno-52-4) ]` 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](#build-dependencies) ------------------------------------------ If a project is structured as [Python package](../config/#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: pyproject.toml `[](#__codelineno-53-1) [project] [](#__codelineno-53-2) name = "pandas" [](#__codelineno-53-3) version = "0.1.0" [](#__codelineno-53-4) [](#__codelineno-53-5) [build-system] [](#__codelineno-53-6) requires = ["setuptools>=42"] [](#__codelineno-53-7) 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`: pyproject.toml `[](#__codelineno-54-1) [project] [](#__codelineno-54-2) name = "pandas" [](#__codelineno-54-3) version = "0.1.0" [](#__codelineno-54-4) [](#__codelineno-54-5) [build-system] [](#__codelineno-54-6) requires = ["setuptools>=42"] [](#__codelineno-54-7) build-backend = "setuptools.build_meta" [](#__codelineno-54-8) [](#__codelineno-54-9) [tool.uv.sources] [](#__codelineno-54-10) 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](#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: `[](#__codelineno-55-1) $ uv add --editable ./path/foo` Or, to opt-out of using an editable dependency in a workspace: `[](#__codelineno-56-1) $ uv add --no-editable ./path/foo` [Dependency specifiers (PEP 508)](#dependency-specifiers-pep-508) ------------------------------------------------------------------ uv uses [dependency specifiers](https://packaging.python.org/en/latest/specifications/dependency-specifiers/) , previously known as [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. Back to top --- # Structure and files | uv [Project structure and files](#project-structure-and-files) ============================================================ [The `pyproject.toml`](#the-pyprojecttoml) ------------------------------------------- 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/) for details. A minimal project definition includes a name and version: pyproject.toml `[](#__codelineno-0-1) [project] [](#__codelineno-0-2) name = "example" [](#__codelineno-0-3) version = "0.1.0"` Additional project metadata and configuration includes: * [Python version requirement](../config/#python-version-requirement) * [Dependencies](../dependencies/) * [Build system](../config/#build-systems) * [Entry points (commands)](../config/#entry-points) [The project environment](#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/) 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/) or [`uv run --with`](../run/#requesting-additional-dependencies) . Tip If you don't want uv to manage the project environment, set [`managed = false`](../../../reference/settings/#managed) to disable automatic locking and syncing of the project. For example: pyproject.toml `[](#__codelineno-1-1) [tool.uv] [](#__codelineno-1-2) managed = false` [The lockfile](#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/#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. There is no Python standard for lockfiles at this time, so the format of this file is specific to uv and not usable by other tools. Back to top --- # Running commands | uv [Running commands in projects](#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: `[](#__codelineno-0-1) $ 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.: ``[](#__codelineno-1-1) $ # Presuming the project provides `example-cli` [](#__codelineno-1-2) $ uv run example-cli foo [](#__codelineno-1-3) [](#__codelineno-1-4) $ # Running a `bash` script that requires the project to be available [](#__codelineno-1-5) $ uv run bash scripts/foo.sh`` [Requesting additional dependencies](#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`: `[](#__codelineno-2-1) $ uv run --with httpx==0.26.0 python -c "import httpx; print(httpx.__version__)" [](#__codelineno-2-2) 0.26.0 [](#__codelineno-2-3) $ uv run --with httpx==0.25.0 python -c "import httpx; print(httpx.__version__)" [](#__codelineno-2-4) 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](#running-scripts) ------------------------------------ Scripts that declare inline metadata are automatically executed in environments isolated from the project. See the [scripts guide](../../../guides/scripts/#declaring-script-dependencies) for more details. For example, given a script: example.py `[](#__codelineno-3-1) # /// script [](#__codelineno-3-2) # dependencies = [ [](#__codelineno-3-3) # "httpx", [](#__codelineno-3-4) # ] [](#__codelineno-3-5) # /// [](#__codelineno-3-6) [](#__codelineno-3-7) import httpx [](#__codelineno-3-8) [](#__codelineno-3-9) resp = httpx.get("https://peps.python.org/api/peps.json") [](#__codelineno-3-10) data = resp.json() [](#__codelineno-3-11) 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 Windows Scripts](#legacy-windows-scripts) -------------------------------------------------- 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. `[](#__codelineno-4-1) $ 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. `[](#__codelineno-5-1) $ uv run --with nuitka==2.6.7 -- nuitka --version` [Signal handling](#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 shells send SIGINT to the foreground process group on Ctrl-C, uv will only forward a SIGINT to the child process if it is seen 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. Back to top --- # Locking and syncing | uv [Locking and syncing](#locking-and-syncing) ============================================ Locking is the process of resolving your project's dependencies into a [lockfile](../layout/#the-lockfile) . Syncing is the process of installing a subset of packages from the lockfile into the [project environment](../layout/#the-project-environment) . [Automatic lock and sync](#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: `[](#__codelineno-0-1) $ 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: `[](#__codelineno-1-1) $ uv run --frozen ...` Similarly, to run a command without checking if the environment is up-to-date, use the `--no-sync` option: `[](#__codelineno-2-1) $ uv run --no-sync ...` [Checking if the lockfile is up-to-date](#checking-if-the-lockfile-is-up-to-date) ---------------------------------------------------------------------------------- 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`: `[](#__codelineno-3-1) $ 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](#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`: `[](#__codelineno-4-1) $ uv lock` [Syncing the environment](#syncing-the-environment) ---------------------------------------------------- While the environment is synced [automatically](#automatic-lock-and-sync) , it may also be explicitly synced using `uv sync`: `[](#__codelineno-5-1) $ uv sync` Syncing the environment manually is especially useful for ensuring your editor has the correct versions of dependencies. ### [Editable installation](#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/#build-systems) documentation for details. ### [Retaining extraneous packages](#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: `[](#__codelineno-6-1) $ uv sync --inexact` ### [Syncing optional dependencies](#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. `[](#__codelineno-7-1) $ uv sync --extra foo` To quickly enable all extras, use the `--all-extras` option. See the [optional dependencies](../dependencies/#optional-dependencies) documentation for details on how to manage optional dependencies. ### [Syncing development 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/#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 `, `--only-group `, and `--no-group ` 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: `[](#__codelineno-8-1) $ uv sync --no-group foo --group foo` The `foo` group would not be installed. See the [development dependencies](../dependencies/#development-dependencies) documentation for details on how to manage development dependencies. [Upgrading locked package versions](#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: `[](#__codelineno-9-1) $ uv lock --upgrade` To upgrade a single package to the latest version, while retaining the locked versions of all other packages: `[](#__codelineno-10-1) $ uv lock --upgrade-package ` To upgrade a single package to a specific version: `[](#__codelineno-11-1) $ uv lock --upgrade-package ==` 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](#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](#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 `: Do not install the given package(s) When these options are used, all of 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. Back to top --- # Using workspaces | uv [Using workspaces](#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](#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: pyproject.toml `[](#__codelineno-0-1) [project] [](#__codelineno-0-2) name = "albatross" [](#__codelineno-0-3) version = "0.1.0" [](#__codelineno-0-4) requires-python = ">=3.12" [](#__codelineno-0-5) dependencies = ["bird-feeder", "tqdm>=4,<5"] [](#__codelineno-0-6) [](#__codelineno-0-7) [tool.uv.sources] [](#__codelineno-0-8) bird-feeder = { workspace = true } [](#__codelineno-0-9) [](#__codelineno-0-10) [tool.uv.workspace] [](#__codelineno-0-11) members = ["packages/*"] [](#__codelineno-0-12) 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/#applications) or [libraries](../init/#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, with the exception of `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](#workspace-sources) ---------------------------------------- Within a workspace, dependencies on workspace members are facilitated via [`tool.uv.sources`](../dependencies/) , as in: pyproject.toml `[](#__codelineno-1-1) [project] [](#__codelineno-1-2) name = "albatross" [](#__codelineno-1-3) version = "0.1.0" [](#__codelineno-1-4) requires-python = ">=3.12" [](#__codelineno-1-5) dependencies = ["bird-feeder", "tqdm>=4,<5"] [](#__codelineno-1-6) [](#__codelineno-1-7) [tool.uv.sources] [](#__codelineno-1-8) bird-feeder = { workspace = true } [](#__codelineno-1-9) [](#__codelineno-1-10) [tool.uv.workspace] [](#__codelineno-1-11) members = ["packages/*"] [](#__codelineno-1-12) [](#__codelineno-1-13) [build-system] [](#__codelineno-1-14) requires = ["hatchling"] [](#__codelineno-1-15) build-backend = "hatchling.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`: pyproject.toml `[](#__codelineno-2-1) [project] [](#__codelineno-2-2) name = "albatross" [](#__codelineno-2-3) version = "0.1.0" [](#__codelineno-2-4) requires-python = ">=3.12" [](#__codelineno-2-5) dependencies = ["bird-feeder", "tqdm>=4,<5"] [](#__codelineno-2-6) [](#__codelineno-2-7) [tool.uv.sources] [](#__codelineno-2-8) bird-feeder = { workspace = true } [](#__codelineno-2-9) tqdm = { git = "https://github.com/tqdm/tqdm" } [](#__codelineno-2-10) [](#__codelineno-2-11) [tool.uv.workspace] [](#__codelineno-2-12) members = ["packages/*"] [](#__codelineno-2-13) [](#__codelineno-2-14) [build-system] [](#__codelineno-2-15) requires = ["hatchling"] [](#__codelineno-2-16) build-backend = "hatchling.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. [Workspace layouts](#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: `[](#__codelineno-3-1) albatross [](#__codelineno-3-2) ├── packages [](#__codelineno-3-3) │ ├── bird-feeder [](#__codelineno-3-4) │ │ ├── pyproject.toml [](#__codelineno-3-5) │ │ └── src [](#__codelineno-3-6) │ │ └── bird_feeder [](#__codelineno-3-7) │ │ ├── __init__.py [](#__codelineno-3-8) │ │ └── foo.py [](#__codelineno-3-9) │ └── seeds [](#__codelineno-3-10) │ ├── pyproject.toml [](#__codelineno-3-11) │ └── src [](#__codelineno-3-12) │ └── seeds [](#__codelineno-3-13) │ ├── __init__.py [](#__codelineno-3-14) │ └── bar.py [](#__codelineno-3-15) ├── pyproject.toml [](#__codelineno-3-16) ├── README.md [](#__codelineno-3-17) ├── uv.lock [](#__codelineno-3-18) └── src [](#__codelineno-3-19) └── albatross [](#__codelineno-3-20) └── 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](#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`: pyproject.toml `[](#__codelineno-4-1) [project] [](#__codelineno-4-2) name = "albatross" [](#__codelineno-4-3) version = "0.1.0" [](#__codelineno-4-4) requires-python = ">=3.12" [](#__codelineno-4-5) dependencies = ["bird-feeder", "tqdm>=4,<5"] [](#__codelineno-4-6) [](#__codelineno-4-7) [tool.uv.sources] [](#__codelineno-4-8) bird-feeder = { path = "packages/bird-feeder" } [](#__codelineno-4-9) [](#__codelineno-4-10) [build-system] [](#__codelineno-4-11) requires = ["hatchling"] [](#__codelineno-4-12) build-backend = "hatchling.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. Back to top --- # Index | uv [Configuration overview](#configuration-overview) ================================================== Read about the various ways to configure uv: * [Using configuration files](files/) * [Using environment variables](environment/) * [Configuring authentication](authentication/) * [Configuring package indexes](indexes/) Or, jump to the [settings reference](../reference/settings/) which enumerates the available configuration options. Back to top --- # Authentication | uv [Authentication](#authentication) ================================== [Git authentication](#git-authentication) ------------------------------------------ uv allows packages to be installed from Git and supports the following schemes for authenticating with private repositories. Using SSH: * `git+ssh://git@/...` (e.g., `git+ssh://[[email protected]](/cdn-cgi/l/email-protection) /astral-sh/uv`) * `git+ssh://git@/...` (e.g., `git+ssh://[[email protected]](/cdn-cgi/l/email-protection) /astral-sh/uv`) 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. Using a password or token: * `git+https://:@/...` (e.g., `git+https://git:[[email protected]](/cdn-cgi/l/email-protection) /astral-sh/uv`) * `git+https://@/...` (e.g., `git+https://[[email protected]](/cdn-cgi/l/email-protection) /astral-sh/uv`) * `git+https://@/...` (e.g., `git+https://[[email protected]](/cdn-cgi/l/email-protection) /astral-sh/uv`) When using a GitHub personal access token, the username is arbitrary. GitHub does not support logging in with password directly, although other hosts may. If a username is provided without credentials, you will be prompted to enter them. If there are no credentials present in the URL and authentication is needed, the [Git credential helper](https://git-scm.com/doc/credential-helpers) will be queried. [HTTP authentication](#http-authentication) -------------------------------------------- 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://:@/...` * A [`.netrc`](https://everything.curl.dev/usingcurl/netrc) configuration file * A [keyring](https://github.com/jaraco/keyring) provider (requires opt-in) If authentication is found for a single net location (scheme, host, and port), it will be cached for the duration of the command and used for other queries to that net location. Authentication is not cached across invocations of uv. `.netrc` authentication is enabled by default, and will respect the `NETRC` environment variable if defined, falling back to `~/.netrc` if not. To enable keyring-based authentication, pass the `--keyring-provider subprocess` command-line argument to uv, or set `UV_KEYRING_PROVIDER=subprocess`. Authentication may be used for hosts specified in the following contexts: * `[index]` * `index-url` * `extra-index-url` * `find-links` * `package @ https://...` See the [index authentication documentation](../indexes/#authentication) for details on authenticating index URLs. See the [`pip` compatibility guide](../../pip/compatibility/#registry-authentication) for details on differences from `pip`. [Authentication with alternative package indexes](#authentication-with-alternative-package-indexes) ---------------------------------------------------------------------------------------------------- See the [alternative indexes integration guide](../../guides/integration/alternative-indexes/) for details on authentication with popular alternative Python package indexes. [Custom CA certificates](#custom-ca-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). 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. 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`. 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. Finally, 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`: `[](#__codelineno-0-1) [tool.uv] [](#__codelineno-0-2) 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. Back to top --- # Environment variables | uv [Environment variables](#environment-variables) ================================================ uv defines and respects the following environment variables: ### [`UV_BREAK_SYSTEM_PACKAGES`](#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`](#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`](#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`](#uv_compile_bytecode) Equivalent to the `--compile-bytecode` command-line argument. If set, uv will compile Python source files to bytecode after installation. ### [`UV_CONCURRENT_BUILDS`](#uv_concurrent_builds) Sets the maximum number of source distributions that uv will build concurrently at any given time. ### [`UV_CONCURRENT_DOWNLOADS`](#uv_concurrent_downloads) Sets the maximum number of in-flight concurrent downloads that uv will perform at any given time. ### [`UV_CONCURRENT_INSTALLS`](#uv_concurrent_installs) Controls the number of threads used when installing and unzipping packages. ### [`UV_CONFIG_FILE`](#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`](#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_CUSTOM_COMPILE_COMMAND`](#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`](#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_ENV_FILE`](#uv_env_file) `.env` files from which to load environment variables when executing `uv run` commands. ### [`UV_EXCLUDE_NEWER`](#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`](#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`](#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`](#uv_fork_strategy) Equivalent to the `--fork-strategy` argument. Controls version selection during universal resolution. ### [`UV_FROZEN`](#uv_frozen) Equivalent to the `--frozen` command-line argument. If set, uv will run without updating the `uv.lock` file. ### [`UV_GITHUB_TOKEN`](#uv_github_token) Equivalent to the `--token` argument for self update. A GitHub token for authentication. ### [`UV_GIT_LFS`](#uv_git_lfs) Enables fetching files stored in Git LFS when installing a package from a Git repository. ### [`UV_HTTP_TIMEOUT`](#uv_http_timeout) Timeout (in seconds) for HTTP requests. (default: 30 s) ### [`UV_INDEX`](#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`](#uv_index_strategy) Equivalent to the `--index-strategy` command-line argument. For example, if set to `unsafe-any-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`](#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`](#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`](#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_INSECURE_HOST`](#uv_insecure_host) Equivalent to the `--allow-insecure-host` argument. ### [`UV_INSTALLER_GHE_BASE_URL`](#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`](#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`](#uv_install_dir) The directory in which to install uv using the standalone installer and `self update` feature. Defaults to `~/.local/bin`. ### [`UV_KEYRING_PROVIDER`](#uv_keyring_provider) Equivalent to the `--keyring-provider` command-line argument. If set, uv will use this value as the keyring provider. ### [`UV_LINK_MODE`](#uv_link_mode) Equivalent to the `--link-mode` command-line argument. If set, uv will use this as a link mode. ### [`UV_LOCKED`](#uv_locked) Equivalent to the `--locked` command-line argument. If set, uv will assert that the `uv.lock` remains unchanged. ### [`UV_LOG_CONTEXT`](#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`](#uv_managed_python) Require use of uv-managed Python versions. ### [`UV_NATIVE_TLS`](#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`](#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`](#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`](#uv_no_build) Equivalent to the `--no-build` command-line argument. If set, uv will not build source distributions. ### [`UV_NO_BUILD_ISOLATION`](#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`](#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`](#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`](#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_ENV_FILE`](#uv_no_env_file) Ignore `.env` files when executing `uv run` commands. ### [`UV_NO_INSTALLER_METADATA`](#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`](#uv_no_managed_python) Disable use of uv-managed Python versions. ### [`UV_NO_PROGRESS`](#uv_no_progress) Equivalent to the `--no-progress` command-line argument. Disables all progress output. For example, spinners and progress bars. ### [`UV_NO_SYNC`](#uv_no_sync) Equivalent to the `--no-sync` command-line argument. If set, uv will skip updating the environment. ### [`UV_NO_VERIFY_HASHES`](#uv_no_verify_hashes) Equivalent to the `--no-verify-hashes` argument. Disables hash verification for `requirements.txt` files. ### [`UV_NO_WRAP`](#uv_no_wrap) Use to disable line wrapping for diagnostics. ### [`UV_OFFLINE`](#uv_offline) Equivalent to the `--offline` command-line argument. If set, uv will disable network access. ### [`UV_OVERRIDE`](#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`](#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`](#uv_preview) Equivalent to the `--preview` argument. Enables preview mode. ### [`UV_PROJECT_ENVIRONMENT`](#uv_project_environment) Specifies the path to the directory to use for a project virtual environment. See the [project documentation](../../concepts/projects/config/#project-environment-path) for more details. ### [`UV_PUBLISH_CHECK_URL`](#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`](#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`](#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`](#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`](#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`](#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`](#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`](#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`](#uv_python_bin_dir) Specifies the directory to place links to installed, managed Python executables. ### [`UV_PYTHON_DOWNLOADS`](#uv_python_downloads) Equivalent to the [`python-downloads`](../../reference/settings/#python-downloads) setting and, when disabled, the `--no-python-downloads` option. Whether uv should allow Python downloads. ### [`UV_PYTHON_INSTALL_DIR`](#uv_python_install_dir) Specifies the directory for storing managed Python installations. ### [`UV_PYTHON_INSTALL_MIRROR`](#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_PREFERENCE`](#uv_python_preference) Whether uv should prefer system or managed Python versions. ### [`UV_REQUEST_TIMEOUT`](#uv_request_timeout) Timeout (in seconds) for HTTP requests. Equivalent to `UV_HTTP_TIMEOUT`. ### [`UV_REQUIRE_HASHES`](#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`](#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_SYSTEM_PYTHON`](#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_TOOL_BIN_DIR`](#uv_tool_bin_dir) Specifies the "bin" directory for installing tool executables. ### [`UV_TOOL_DIR`](#uv_tool_dir) Specifies the directory where uv stores managed tools. ### [`UV_TORCH_BACKEND`](#uv_torch_backend) Equivalent to the `--torch-backend` command-line argument (e.g., `cpu`, `cu126`, or `auto`). ### [`UV_UNMANAGED_INSTALL`](#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_SEED`](#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](#externally-defined-variables) -------------------------------------------------------------- uv also reads the following externally defined environment variables: ### [`ACTIONS_ID_TOKEN_REQUEST_TOKEN`](#actions_id_token_request_token) Used for trusted publishing via `uv publish`. Contains the oidc request token. ### [`ACTIONS_ID_TOKEN_REQUEST_URL`](#actions_id_token_request_url) Used for trusted publishing via `uv publish`. Contains the oidc token url. ### [`ALL_PROXY`](#all_proxy) General proxy for all network requests. ### [`APPDATA`](#appdata) Path to user-level configuration directory on Windows systems. ### [`BASH_VERSION`](#bash_version) Used to detect Bash shell usage. ### [`CLICOLOR_FORCE`](#clicolor_force) Use to control color via `anstyle`. ### [`COLUMNS`](#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`](#conda_default_env) Used to determine if an active Conda environment is the base environment or not. ### [`CONDA_PREFIX`](#conda_prefix) Used to detect an activated Conda environment. ### [`FISH_VERSION`](#fish_version) Used to detect Fish shell usage. ### [`FORCE_COLOR`](#force_color) Forces colored output regardless of terminal support. See [force-color.org](https://force-color.org) . ### [`GITHUB_ACTIONS`](#github_actions) Used for trusted publishing via `uv publish`. ### [`HOME`](#home) The standard `HOME` env var. ### [`HTTPS_PROXY`](#https_proxy) Proxy for HTTPS requests. ### [`HTTP_PROXY`](#http_proxy) Proxy for HTTP requests. ### [`HTTP_TIMEOUT`](#http_timeout) Timeout (in seconds) for HTTP requests. Equivalent to `UV_HTTP_TIMEOUT`. ### [`INSTALLER_NO_MODIFY_PATH`](#installer_no_modify_path) Avoid modifying the `PATH` environment variable when installing uv using the standalone installer and `self update` feature. ### [`JPY_SESSION_NAME`](#jpy_session_name) Used to detect when running inside a Jupyter notebook. ### [`KSH_VERSION`](#ksh_version) Used to detect Ksh shell usage. ### [`LOCALAPPDATA`](#localappdata) Used to look for Microsoft Store Pythons installations. ### [`MACOSX_DEPLOYMENT_TARGET`](#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 `12.0`, the least-recent non-EOL macOS version at time of writing. ### [`NETRC`](#netrc) Use to set the .netrc file location. ### [`NO_COLOR`](#no_color) Disables colored output (takes precedence over `FORCE_COLOR`). See [no-color.org](https://no-color.org) . ### [`NU_VERSION`](#nu_version) Used to detect `NuShell` usage. ### [`PAGER`](#pager) The standard `PAGER` posix env var. Used by `uv` to configure the appropriate pager. ### [`PATH`](#path) The standard `PATH` env var. ### [`PROMPT`](#prompt) Used to detect the use of the Windows Command Prompt (as opposed to PowerShell). ### [`PWD`](#pwd) The standard `PWD` posix env var. ### [`PYC_INVALIDATION_MODE`](#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`](#pythonpath) Adds directories to Python module search path (e.g., `PYTHONPATH=/path/to/modules`). ### [`RUST_LOG`](#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`](#rust_min_stack) Use to set the stack size used by uv. The value is in bytes, and the default is typically 2MB (2097152). 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, 4MB)`. ### [`SHELL`](#shell) The standard `SHELL` posix env var. ### [`SSL_CERT_FILE`](#ssl_cert_file) Custom certificate bundle file path for SSL connections. ### [`SSL_CLIENT_CERT`](#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`](#systemdrive) Path to system-level configuration directory on Windows systems. ### [`TRACING_DURATIONS_FILE`](#tracing_durations_file) Use to create the tracing durations file via the `tracing-durations-export` feature. ### [`USERPROFILE`](#userprofile) Path to root directory of user's profile on Windows systems. ### [`UV`](#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](https://doc.rust-lang.org/std/env/fn.current_exe.html#security) for security considerations. ### [`VIRTUAL_ENV`](#virtual_env) Used to detect an activated virtual environment. ### [`VIRTUAL_ENV_DISABLE_PROMPT`](#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`](#xdg_bin_home) Path to directory where executables are installed. ### [`XDG_CACHE_HOME`](#xdg_cache_home) Path to cache directory on Unix systems. ### [`XDG_CONFIG_DIRS`](#xdg_config_dirs) Path to system-level configuration directory on Unix systems. ### [`XDG_CONFIG_HOME`](#xdg_config_home) Path to user-level configuration directory on Unix systems. ### [`XDG_DATA_HOME`](#xdg_data_home) Path to directory for storing managed Python installations and tools. ### [`ZDOTDIR`](#zdotdir) Used to determine which `.zshenv` to use when Zsh is being used. ### [`ZSH_VERSION`](#zsh_version) Used to detect Zsh shell usage. Back to top --- # Installer | uv [Configuring the uv installer](#configuring-the-uv-installer) ============================================================== [Changing the install path](#changing-the-install-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 LinuxWindows `[](#__codelineno-0-1) $ curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="/custom/path" sh` `[](#__codelineno-1-1) powershell -ExecutionPolicy ByPass -c {$env:UV_INSTALL_DIR = "C:\Custom\Path";irm https://astral.sh/uv/install.ps1 | iex}` [Disabling shell modifications](#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 `INSTALLER_NO_MODIFY_PATH`. For example: `[](#__codelineno-2-1) $ curl -LsSf https://astral.sh/uv/install.sh | env INSTALLER_NO_MODIFY_PATH=1 sh` If installed with `INSTALLER_NO_MODIFY_PATH`, subsequent operations, like `uv self update`, will not modify your shell profiles. [Unmanaged installations](#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: `[](#__codelineno-3-1) $ 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 install script](#passing-options-to-the-install-script) -------------------------------------------------------------------------------- Using environment variables is recommended because they are consistent across platforms. However, options can be passed directly to the install script. For example, to see the available options: `[](#__codelineno-4-1) $ curl -LsSf https://astral.sh/uv/install.sh | sh -s -- --help` Back to top --- # Package indexes | uv [Package indexes](#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](#defining-an-index) ---------------------------------------- To include an additional index when resolving dependencies, add a `[[tool.uv.index]]` entry to your `pyproject.toml`: `[](#__codelineno-0-1) [[tool.uv.index]] [](#__codelineno-0-2) # Optional name for the index. [](#__codelineno-0-3) name = "pytorch" [](#__codelineno-0-4) # Required URL for the index. [](#__codelineno-0-5) 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): `[](#__codelineno-1-1) [[tool.uv.index]] [](#__codelineno-1-2) name = "pytorch" [](#__codelineno-1-3) url = "https://download.pytorch.org/whl/cpu" [](#__codelineno-1-4) 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 `=` syntax, as in: `[](#__codelineno-2-1) # On the command line. [](#__codelineno-2-2) $ uv lock --index pytorch=https://download.pytorch.org/whl/cpu [](#__codelineno-2-3) # Via an environment variable. [](#__codelineno-2-4) $ UV_INDEX=pytorch=https://download.pytorch.org/whl/cpu uv lock` [Pinning a package to an index](#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`: `[](#__codelineno-3-1) [tool.uv.sources] [](#__codelineno-3-2) torch = { index = "pytorch" } [](#__codelineno-3-3) [](#__codelineno-3-4) [[tool.uv.index]] [](#__codelineno-3-5) name = "pytorch" [](#__codelineno-3-6) 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: pyproject.toml `[](#__codelineno-4-1) [project] [](#__codelineno-4-2) dependencies = ["torch"] [](#__codelineno-4-3) [](#__codelineno-4-4) [tool.uv.sources] [](#__codelineno-4-5) torch = [ [](#__codelineno-4-6) { index = "pytorch-cu118", marker = "sys_platform == 'darwin'"}, [](#__codelineno-4-7) { index = "pytorch-cu124", marker = "sys_platform != 'darwin'"}, [](#__codelineno-4-8) ] [](#__codelineno-4-9) [](#__codelineno-4-10) [[tool.uv.index]] [](#__codelineno-4-11) name = "pytorch-cu118" [](#__codelineno-4-12) url = "https://download.pytorch.org/whl/cu118" [](#__codelineno-4-13) [](#__codelineno-4-14) [[tool.uv.index]] [](#__codelineno-4-15) name = "pytorch-cu124" [](#__codelineno-4-16) 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`: `[](#__codelineno-5-1) [tool.uv.sources] [](#__codelineno-5-2) torch = { index = "pytorch" } [](#__codelineno-5-3) [](#__codelineno-5-4) [[tool.uv.index]] [](#__codelineno-5-5) name = "pytorch" [](#__codelineno-5-6) url = "https://download.pytorch.org/whl/cpu" [](#__codelineno-5-7) 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](#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. Users can opt in to alternate index behaviors 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. * `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](#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/) for details on authenticating with specific private index providers, e.g., from AWS, Azure, or GCP. ### [Providing credentials directly](#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`: `[](#__codelineno-6-1) [[tool.uv.index]] [](#__codelineno-6-2) name = "internal-proxy" [](#__codelineno-6-3) 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: `[](#__codelineno-7-1) export UV_INDEX_INTERNAL_PROXY_USERNAME=public [](#__codelineno-7-2) 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: `[](#__codelineno-8-1) [[tool.uv.index]] [](#__codelineno-8-2) name = "internal" [](#__codelineno-8-3) url = "https://public:[[email protected]](/cdn-cgi/l/email-protection) /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](#using-credential-providers) In addition to providing credentials directly, uv supports discovery of credentials from netrc and keyring. See the [HTTP authentication](../authentication/#http-authentication) 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: `[](#__codelineno-9-1) [[tool.uv.index]] [](#__codelineno-9-2) name = "example" [](#__codelineno-9-3) url = "https://example.com/simple" [](#__codelineno-9-4) authenticate = "always"` When `authenticate` is set to `always`, uv will eagerly search for credentials and error if credentials cannot be found. ### [Disabling authentication](#disabling-authentication) To prevent leaking credentials, authentication can be disabled for an index: `[](#__codelineno-10-1) [[tool.uv.index]] [](#__codelineno-10-2) name = "example" [](#__codelineno-10-3) url = "https://example.com/simple" [](#__codelineno-10-4) 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. [`--index-url` and `--extra-index-url`](#-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`. Back to top --- # Configuration files | uv [Configuration files](#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`: pyproject.toml `[](#__codelineno-0-1) [[tool.uv.index]] [](#__codelineno-0-2) url = "https://test.pypi.org/simple" [](#__codelineno-0-3) 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: uv.toml `[](#__codelineno-1-1) [[index]] [](#__codelineno-1-2) url = "https://test.pypi.org/simple" [](#__codelineno-1-3) 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](#settings) ---------------------- See the [settings reference](../../reference/settings/) for an enumeration of the available settings. [`.env`](#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: `[](#__codelineno-2-1) $ echo "MY_VAR='Hello, world!'" > .env [](#__codelineno-2-2) $ uv run --env-file .env -- python -c 'import os; print(os.getenv("MY_VAR"))' [](#__codelineno-2-3) 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](#configuring-the-pip-interface) ---------------------------------------------------------------- A dedicated [`[tool.uv.pip]`](../../reference/settings/#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`): pyproject.toml `[](#__codelineno-3-1) [tool.uv.pip] [](#__codelineno-3-2) index-url = "https://test.pypi.org/simple"` Back to top --- # Index | uv [Getting started](#getting-started) ==================================== To help you get started with uv, we'll cover a few important topics: * [Installing uv](installation/) * [First steps after installation](first-steps/) * [An overview of uv's features](features/) * [How to get help](help/) Read on, or jump ahead to another section: * Get going quickly with [guides](../guides/) for common workflows. * Learn more about the core [concepts](../concepts/) in uv. * Use the [reference](../reference/) documentation to find details about something specific. Back to top --- # Features | uv [Features](#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](#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/) to get started. [Scripts](#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/) to get started. [Projects](#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/) to get started. [Tools](#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/) to get started. [The pip interface](#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/) 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/) 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/) 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/) for details. [Utility](#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](#next-steps) -------------------------- Read the [guides](../../guides/) for an introduction to each feature, check out [concept](../../concepts/) pages for in-depth details about uv's features, or learn how to [get help](../help/) if you run into any problems. Back to top --- # Getting help | uv [Getting help](#getting-help) ============================== [Help menus](#help-menus) -------------------------- The `--help` flag can be used to view the help menu for a command, e.g., for `uv`: `[](#__codelineno-0-1) $ uv --help` To view the help menu for a specific command, e.g., for `uv init`: `[](#__codelineno-1-1) $ 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`: `[](#__codelineno-2-1) $ uv help` To view the long help menu for a specific command, e.g., for `uv init`: `[](#__codelineno-3-1) $ 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`. [Viewing the version](#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: `[](#__codelineno-4-1) $ uv version` The following are also valid: ``[](#__codelineno-5-1) $ uv --version # Same output as `uv version` [](#__codelineno-5-2) $ uv -V # Will not include the build commit and date [](#__codelineno-5-3) $ uv pip --version # Can be used with a subcommand`` [Troubleshooting issues](#troubleshooting-issues) -------------------------------------------------- The reference documentation contains a [troubleshooting guide](../../reference/troubleshooting/) for common issues. [Open an issue on GitHub](#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](#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. Back to top --- # First steps | uv [First steps with uv](#first-steps-with-uv) ============================================ After [installing uv](../installation/) , you can check that uv is available by running the `uv` command: `[](#__codelineno-0-1) $ uv [](#__codelineno-0-2) An extremely fast Python package manager. [](#__codelineno-0-3) [](#__codelineno-0-4) Usage: uv [OPTIONS] [](#__codelineno-0-5) [](#__codelineno-0-6) ...` You should see a help menu listing the available commands. [Next steps](#next-steps) -------------------------- Now that you've confirmed uv is installed, check out an [overview of features](../features/) , learn how to [get help](../help/) if you run into any problems, or jump to the [guides](../../guides/) to start using uv. Back to top --- # Installation | uv [Installing uv](#installing-uv) ================================ [Installation methods](#installation-methods) ---------------------------------------------- Install uv with our standalone installers or your package manager of choice. ### [Standalone installer](#standalone-installer) uv provides a standalone installer to download and install uv: macOS and LinuxWindows Use `curl` to download the script and execute it with `sh`: `[](#__codelineno-0-1) $ curl -LsSf https://astral.sh/uv/install.sh | sh` If your system doesn't have `curl`, you can use `wget`: `[](#__codelineno-1-1) $ wget -qO- https://astral.sh/uv/install.sh | sh` Request a specific version by including it in the URL: `[](#__codelineno-2-1) $ curl -LsSf https://astral.sh/uv/0.6.10/install.sh | sh` Use `irm` to download the script and execute it with `iex`: `[](#__codelineno-3-1) $ 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: `[](#__codelineno-4-1) $ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/0.6.10/install.ps1 | iex"` Tip The installation script may be inspected before use: macOS and LinuxWindows `[](#__codelineno-5-1) $ curl -LsSf https://astral.sh/uv/install.sh | less` `[](#__codelineno-6-1) $ 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 documentation on [installer configuration](../../configuration/installer/) for details on customizing your uv installation. ### [PyPI](#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`: `[](#__codelineno-7-1) $ pipx install uv` However, `pip` can also be used: `[](#__codelineno-8-1) $ 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. ### [Cargo](#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. `[](#__codelineno-9-1) $ cargo install --git https://github.com/astral-sh/uv uv` ### [Homebrew](#homebrew) uv is available in the core Homebrew packages. `[](#__codelineno-10-1) $ brew install uv` ### [WinGet](#winget) uv is available via [WinGet](https://winstall.app/apps/astral-sh.uv) . `[](#__codelineno-11-1) $ winget install --id=astral-sh.uv -e` ### [Scoop](#scoop) uv is available via [Scoop](https://scoop.sh/#/apps?q=uv) . `[](#__codelineno-12-1) $ scoop install main/uv` ### [Docker](#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/) for more details. ### [GitHub Releases](#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`. [Upgrading uv](#upgrading-uv) ------------------------------ When uv is installed via the standalone installer, it can update itself on-demand: `[](#__codelineno-13-1) $ uv self update` Tip Updating uv will re-run the installer and can modify your shell profiles. To disable this behavior, set `INSTALLER_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`: `[](#__codelineno-14-1) $ pip install --upgrade uv` [Shell autocompletion](#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: BashZshfishElvishPowerShell / pwsh `[](#__codelineno-15-1) echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc` `[](#__codelineno-16-1) echo 'eval "$(uv generate-shell-completion zsh)"' >> ~/.zshrc` `[](#__codelineno-17-1) echo 'uv generate-shell-completion fish | source' >> ~/.config/fish/config.fish` `[](#__codelineno-18-1) echo 'eval (uv generate-shell-completion elvish | slurp)' >> ~/.elvish/rc.elv` `[](#__codelineno-19-1) if (!(Test-Path -Path $PROFILE)) { [](#__codelineno-19-2) New-Item -ItemType File -Path $PROFILE -Force [](#__codelineno-19-3) } [](#__codelineno-19-4) 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: BashZshfishElvishPowerShell / pwsh `[](#__codelineno-20-1) echo 'eval "$(uvx --generate-shell-completion bash)"' >> ~/.bashrc` `[](#__codelineno-21-1) echo 'eval "$(uvx --generate-shell-completion zsh)"' >> ~/.zshrc` `[](#__codelineno-22-1) echo 'uvx --generate-shell-completion fish | source' >> ~/.config/fish/config.fish` `[](#__codelineno-23-1) echo 'eval (uvx --generate-shell-completion elvish | slurp)' >> ~/.elvish/rc.elv` `[](#__codelineno-24-1) if (!(Test-Path -Path $PROFILE)) { [](#__codelineno-24-2) New-Item -ItemType File -Path $PROFILE -Force [](#__codelineno-24-3) } [](#__codelineno-24-4) 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](#uninstallation) ---------------------------------- If you need to remove uv from your system, follow these steps: 1. Clean up stored data (optional): `[](#__codelineno-25-1) $ uv cache clean [](#__codelineno-25-2) $ rm -r "$(uv python dir)" [](#__codelineno-25-3) $ 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 and uvx binaries: macOS and LinuxWindows `[](#__codelineno-26-1) $ rm ~/.local/bin/uv ~/.local/bin/uvx` `[](#__codelineno-27-1) $ rm $HOME\.local\bin\uv.exe [](#__codelineno-27-2) $ rm $HOME\.local\bin\uvx.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](#next-steps) -------------------------- See the [first steps](../first-steps/) or jump straight to the [guides](../../guides/) to start using uv. Back to top --- # Index | uv [Guides overview](#guides-overview) ==================================== Check out one of the core guides to get started: * [Installing Python versions](install-python/) * [Running scripts and declaring dependencies](scripts/) * [Running and installing applications as tools](tools/) * [Creating and working on projects](projects/) * [Building and publishing packages](package/) * [Integrate uv with other software, e.g., Docker, GitHub, PyTorch, and more](integration/) Or, explore the [concept documentation](../concepts/) for comprehensive breakdown of each feature. Back to top --- # Installing and managing Python | uv [Installing Python](#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](#getting-started) ------------------------------------ To install the latest Python version: `[](#__codelineno-0-1) $ 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/#managed-python-distributions) documentation for more details. Once Python is installed, it will be used by `uv` commands automatically. Important When Python is installed by uv, it will not be available globally (i.e. via the `python` command). Support for this feature is in _preview_. See [Installing Python executables](../../concepts/python-versions/#installing-python-executables) for details. You can still use [`uv run`](../scripts/#using-different-python-versions) or [create and activate a virtual environment](../../pip/environments/) to use `python` directly. [Installing a specific version](#installing-a-specific-version) ---------------------------------------------------------------- To install a specific Python version: `[](#__codelineno-1-1) $ uv python install 3.12` To install multiple Python versions: `[](#__codelineno-2-1) $ uv python install 3.11 3.12` To install an alternative Python implementation, e.g., PyPy: `[](#__codelineno-3-1) $ uv python install [[email protected]](/cdn-cgi/l/email-protection)` See the [`python install`](../../concepts/python-versions/#installing-a-python-version) documentation for more details. [Reinstalling Python](#reinstalling-python) -------------------------------------------- To reinstall uv-managed Python versions, use `--reinstall`, e.g.: `[](#__codelineno-4-1) $ 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](#viewing-python-installations) -------------------------------------------------------------- To view available and installed Python versions: `[](#__codelineno-5-1) $ uv python list` See the [`python list`](../../concepts/python-versions/#viewing-available-python-versions) documentation for more details. [Automatic Python downloads](#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: `[](#__codelineno-6-1) $ uvx [[email protected]](/cdn-cgi/l/email-protection) -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: `[](#__codelineno-7-1) $ uv venv` Tip Automatic Python downloads can be [easily disabled](../../concepts/python-versions/#disabling-automatic-python-downloads) if you want more control over when Python is downloaded. [Using existing Python versions](#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/#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/#requiring-or-disabling-managed-python-versions) documentation for more details. [Next steps](#next-steps) -------------------------- To learn more about `uv python`, see the [Python version concept](../../concepts/python-versions/) page and the [command reference](../../reference/cli/#uv-python) . Or, read on to learn how to [run scripts](../scripts/) and invoke Python with uv. Back to top --- # Building and publishing a package | uv [Building and publishing a package](#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](#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/#build-systems) documentation. Note If you have internal packages that you do not want to be published, you can mark them as private: `[](#__codelineno-0-1) [project] [](#__codelineno-0-2) 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 tokens: Without a PyPI token matching the project, it can't be accidentally published. [Building your package](#building-your-package) ------------------------------------------------ Build your package with `uv build`: `[](#__codelineno-1-1) $ 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 ` will build the package in the specified directory, while `uv build --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) . [Publishing your package](#publishing-your-package) ---------------------------------------------------- Publish your package with `uv publish`: `[](#__codelineno-2-1) $ 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, 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 `. For example: `[](#__codelineno-3-1) [[tool.uv.index]] [](#__codelineno-3-2) name = "testpypi" [](#__codelineno-3-3) url = "https://test.pypi.org/simple/" [](#__codelineno-3-4) publish-url = "https://test.pypi.org/legacy/" [](#__codelineno-3-5) explicit = true` Note When using `uv publish --index `, 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 ` with the index URL (not the publish 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](#installing-your-package) ---------------------------------------------------- Test that the package can be installed and imported with `uv run`: `[](#__codelineno-4-1) $ uv run --with --no-project -- python -c "import "` 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 ` option to avoid using a cached version of the package. [Next steps](#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/) on integrating uv with other software. Back to top --- # Working on projects | uv [Working on projects](#working-on-projects) ============================================ uv supports managing Python projects, which define their dependencies in a `pyproject.toml` file. [Creating a new project](#creating-a-new-project) -------------------------------------------------- You can create a new Python project using the `uv init` command: `[](#__codelineno-0-1) $ uv init hello-world [](#__codelineno-0-2) $ cd hello-world` Alternatively, you can initialize a project in the working directory: `[](#__codelineno-1-1) $ mkdir hello-world [](#__codelineno-1-2) $ cd hello-world [](#__codelineno-1-3) $ uv init` uv will create the following files: `[](#__codelineno-2-1) . [](#__codelineno-2-2) ├── .python-version [](#__codelineno-2-3) ├── README.md [](#__codelineno-2-4) ├── main.py [](#__codelineno-2-5) └── pyproject.toml` The `main.py` file contains a simple "Hello world" program. Try it out with `uv run`: `[](#__codelineno-3-1) $ uv run main.py [](#__codelineno-3-2) Hello from hello-world!` [Project structure](#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: `[](#__codelineno-4-1) . [](#__codelineno-4-2) ├── .venv [](#__codelineno-4-3) │   ├── bin [](#__codelineno-4-4) │   ├── lib [](#__codelineno-4-5) │   └── pyvenv.cfg [](#__codelineno-4-6) ├── .python-version [](#__codelineno-4-7) ├── README.md [](#__codelineno-4-8) ├── main.py [](#__codelineno-4-9) ├── pyproject.toml [](#__codelineno-4-10) └── uv.lock` ### [`pyproject.toml`](#pyprojecttoml) The `pyproject.toml` contains metadata about your project: pyproject.toml `[](#__codelineno-5-1) [project] [](#__codelineno-5-2) name = "hello-world" [](#__codelineno-5-3) version = "0.1.0" [](#__codelineno-5-4) description = "Add your description here" [](#__codelineno-5-5) readme = "README.md" [](#__codelineno-5-6) 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](../../configuration/files/) in a [`[tool.uv]`](../../reference/settings/) section. ### [`.python-version`](#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`](#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/#the-project-environment) documentation for more details. ### [`uv.lock`](#uvlock) `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/#the-lockfile) documentation for more details. [Managing dependencies](#managing-dependencies) ------------------------------------------------ You can add dependencies to your `pyproject.toml` with the `uv add` command. This will also update the lockfile and project environment: `[](#__codelineno-6-1) $ uv add requests` You can also specify version constraints or alternative sources: `[](#__codelineno-7-1) $ # Specify a version constraint [](#__codelineno-7-2) $ uv add 'requests==2.31.0' [](#__codelineno-7-3) [](#__codelineno-7-4) $ # Add a git dependency [](#__codelineno-7-5) $ 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: ``[](#__codelineno-8-1) $ # Add all dependencies from `requirements.txt`. [](#__codelineno-8-2) $ uv add -r requirements.txt -c constraints.txt`` To remove a package, you can use `uv remove`: `[](#__codelineno-9-1) $ uv remove requests` To upgrade a package, run `uv lock` with the `--upgrade-package` flag: `[](#__codelineno-10-1) $ 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/) for more details. [Running commands](#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`: `[](#__codelineno-11-1) $ uv add flask [](#__codelineno-11-2) $ uv run -- flask run -p 3000` Or, to run a script: example.py `[](#__codelineno-12-1) # Require a project dependency [](#__codelineno-12-2) import flask [](#__codelineno-12-3) [](#__codelineno-12-4) print("hello world")` `[](#__codelineno-13-1) $ uv run example.py` Alternatively, you can use `uv sync` to manually update the environment then activate it before executing a command: macOS and LinuxWindows `[](#__codelineno-14-1) $ uv sync [](#__codelineno-14-2) $ source .venv/bin/activate [](#__codelineno-14-3) $ flask run -p 3000 [](#__codelineno-14-4) $ python example.py` `[](#__codelineno-15-1) uv sync [](#__codelineno-15-2) source .venv\Scripts\activate [](#__codelineno-15-3) flask run -p 3000 [](#__codelineno-15-4) 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/) in projects for more details. [Building distributions](#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: `[](#__codelineno-16-1) $ uv build [](#__codelineno-16-2) $ ls dist/ [](#__codelineno-16-3) hello-world-0.1.0-py3-none-any.whl [](#__codelineno-16-4) hello-world-0.1.0.tar.gz` See the documentation on [building projects](../../concepts/projects/build/) for more details. [Next steps](#next-steps) -------------------------- To learn more about working on projects with uv, see the [projects concept](../../concepts/projects/) page and the [command reference](../../reference/cli/#uv) . Or, read on to learn how to [build and publish your project to a package index](../package/) . Back to top --- # Using alternative package indexes | uv [Using alternative package indexes](#using-alternative-package-indexes) ======================================================================== While uv uses the official Python Package Index (PyPI) by default, it also supports [alternative package indexes](../../../configuration/indexes/) . 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/#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](#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: pyproject.toml `[](#__codelineno-0-1) [[tool.uv.index]] [](#__codelineno-0-2) name = "private-registry" [](#__codelineno-0-3) url = "https://pkgs.dev.azure.com///_packaging//pypi/simple/"` ### [Authenticate with an Azure access token](#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: `[](#__codelineno-1-1) export UV_INDEX_PRIVATE_REGISTRY_USERNAME=dummy [](#__codelineno-1-2) 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`](#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/#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`. `[](#__codelineno-2-1) # Pre-install keyring and the Artifacts plugin from the public PyPI [](#__codelineno-2-2) uv tool install keyring --with artifacts-keyring [](#__codelineno-2-3) [](#__codelineno-2-4) # Enable keyring authentication [](#__codelineno-2-5) export UV_KEYRING_PROVIDER=subprocess [](#__codelineno-2-6) [](#__codelineno-2-7) # Set the username for the index [](#__codelineno-2-8) export UV_INDEX_PRIVATE_REGISTRY_USERNAME=VssSessionToken` Note The [`tool.uv.keyring-provider`](../../../reference/settings/#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](#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/) . First, add a `publish-url` to the index you want to publish packages to. For example: pyproject.toml `[](#__codelineno-3-1) [[tool.uv.index]] [](#__codelineno-3-2) name = "private-registry" [](#__codelineno-3-3) url = "https://pkgs.dev.azure.com///_packaging//pypi/simple/" [](#__codelineno-3-4) publish-url = "https://pkgs.dev.azure.com///_packaging//pypi/upload/"` Then, configure credentials (if not using keyring): `[](#__codelineno-4-1) $ export UV_PUBLISH_USERNAME=dummy [](#__codelineno-4-2) $ export UV_PUBLISH_PASSWORD="$AZURE_ARTIFACTS_TOKEN"` And publish the package: `[](#__codelineno-5-1) $ uv publish --index private-registry` To use `uv publish` without adding the `publish-url` to the project, you can set `UV_PUBLISH_URL`: `[](#__codelineno-6-1) $ export UV_PUBLISH_URL=https://pkgs.dev.azure.com///_packaging//pypi/upload/ [](#__codelineno-6-2) $ uv publish` Note this method is not preferable because uv cannot check if the package is already published before uploading artifacts. [Google Artifact Registry](#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: pyproject.toml `[](#__codelineno-7-1) [[tool.uv.index]] [](#__codelineno-7-2) name = "private-registry" [](#__codelineno-7-3) url = "https://-python.pkg.dev//"` ### [Authenticate with a Google access token](#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`: `[](#__codelineno-8-1) export ARTIFACT_REGISTRY_TOKEN=$( [](#__codelineno-8-2) gcloud auth application-default print-access-token [](#__codelineno-8-3) )` 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: `[](#__codelineno-9-1) export UV_INDEX_PRIVATE_REGISTRY_USERNAME=oauth2accesstoken [](#__codelineno-9-2) 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`](#authenticate-with-keyring-and-keyringsgoogle-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/#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`. `[](#__codelineno-10-1) # Pre-install keyring and Artifact Registry plugin from the public PyPI [](#__codelineno-10-2) uv tool install keyring --with keyrings.google-artifactregistry-auth [](#__codelineno-10-3) [](#__codelineno-10-4) # Enable keyring authentication [](#__codelineno-10-5) export UV_KEYRING_PROVIDER=subprocess [](#__codelineno-10-6) [](#__codelineno-10-7) # Set the username for the index [](#__codelineno-10-8) export UV_INDEX_PRIVATE_REGISTRY_USERNAME=oauth2accesstoken` Note The [`tool.uv.keyring-provider`](../../../reference/settings/#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](#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/) . First, add a `publish-url` to the index you want to publish packages to. For example: pyproject.toml `[](#__codelineno-11-1) [[tool.uv.index]] [](#__codelineno-11-2) name = "private-registry" [](#__codelineno-11-3) url = "https://-python.pkg.dev//" [](#__codelineno-11-4) publish-url = "https://-python.pkg.dev//"` Then, configure credentials (if not using keyring): `[](#__codelineno-12-1) $ export UV_PUBLISH_USERNAME=oauth2accesstoken [](#__codelineno-12-2) $ export UV_PUBLISH_PASSWORD="$ARTIFACT_REGISTRY_TOKEN"` And publish the package: `[](#__codelineno-13-1) $ uv publish --index private-registry` To use `uv publish` without adding the `publish-url` to the project, you can set `UV_PUBLISH_URL`: `[](#__codelineno-14-1) $ export UV_PUBLISH_URL=https://-python.pkg.dev// [](#__codelineno-14-2) $ uv publish` Note this method is not preferable because uv cannot check if the package is already published before uploading artifacts. [AWS CodeArtifact](#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: pyproject.toml `[](#__codelineno-15-1) [[tool.uv.index]] [](#__codelineno-15-2) name = "private-registry" [](#__codelineno-15-3) url = "https://-.d.codeartifact..amazonaws.com/pypi//simple/"` ### [Authenticate with an AWS access token](#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`: `[](#__codelineno-16-1) export AWS_CODEARTIFACT_TOKEN="$( [](#__codelineno-16-2) aws codeartifact get-authorization-token \ [](#__codelineno-16-3) --domain \ [](#__codelineno-16-4) --domain-owner \ [](#__codelineno-16-5) --query authorizationToken \ [](#__codelineno-16-6) --output text [](#__codelineno-16-7) )"` 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: `[](#__codelineno-17-1) export UV_INDEX_PRIVATE_REGISTRY_USERNAME=aws [](#__codelineno-17-2) 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`](#authenticate-with-keyring-and-keyringscodeartifact) 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/#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`. `[](#__codelineno-18-1) # Pre-install keyring and AWS CodeArtifact plugin from the public PyPI [](#__codelineno-18-2) uv tool install keyring --with keyrings.codeartifact [](#__codelineno-18-3) [](#__codelineno-18-4) # Enable keyring authentication [](#__codelineno-18-5) export UV_KEYRING_PROVIDER=subprocess [](#__codelineno-18-6) [](#__codelineno-18-7) # Set the username for the index [](#__codelineno-18-8) export UV_INDEX_PRIVATE_REGISTRY_USERNAME=aws` Note The [`tool.uv.keyring-provider`](../../../reference/settings/#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](#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/) . First, add a `publish-url` to the index you want to publish packages to. For example: pyproject.toml `[](#__codelineno-19-1) [[tool.uv.index]] [](#__codelineno-19-2) name = "private-registry" [](#__codelineno-19-3) url = "https://-.d.codeartifact..amazonaws.com/pypi//simple/" [](#__codelineno-19-4) publish-url = "https://-.d.codeartifact..amazonaws.com/pypi//"` Then, configure credentials (if not using keyring): `[](#__codelineno-20-1) $ export UV_PUBLISH_USERNAME=aws [](#__codelineno-20-2) $ export UV_PUBLISH_PASSWORD="$AWS_CODEARTIFACT_TOKEN"` And publish the package: `[](#__codelineno-21-1) $ uv publish --index private-registry` To use `uv publish` without adding the `publish-url` to the project, you can set `UV_PUBLISH_URL`: `[](#__codelineno-22-1) $ export UV_PUBLISH_URL=https://-.d.codeartifact..amazonaws.com/pypi// [](#__codelineno-22-2) $ uv publish` Note this method is not preferable because uv cannot check if the package is already published before uploading artifacts. [Other package indexes](#other-package-indexes) ------------------------------------------------ uv is also known to work with JFrog's Artifactory. Back to top --- # Using tools | uv [Using tools](#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](#running-tools) -------------------------------- The `uvx` command invokes a tool without installing it. For example, to run `ruff`: `[](#__codelineno-0-1) $ uvx ruff` Note This is exactly equivalent to: `[](#__codelineno-1-1) $ uv tool run ruff` `uvx` is provided as an alias for convenience. Arguments can be provided after the tool name: `[](#__codelineno-2-1) $ uvx pycowsay hello from uv [](#__codelineno-2-2) [](#__codelineno-2-3) ------------- [](#__codelineno-2-4) < hello from uv > [](#__codelineno-2-5) ------------- [](#__codelineno-2-6) \ ^__^ [](#__codelineno-2-7) \ (oo)\_______ [](#__codelineno-2-8) (__)\ )\/\ [](#__codelineno-2-9) ||----w | [](#__codelineno-2-10) || ||` Tools are installed into temporary, isolated environments when using `uvx`. Note If you are running a tool in a [_project_](../../concepts/projects/) and the tool requires that your project is installed, e.g., when using `pytest` or `mypy`, you'll want to use [`uv run`](../projects/#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](#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`: `[](#__codelineno-3-1) $ uvx --from httpie http` [Requesting specific versions](#requesting-specific-versions) -------------------------------------------------------------- To run a tool at a specific version, use `command@`: `[](#__codelineno-4-1) $ uvx [[email protected]](/cdn-cgi/l/email-protection) check` To run a tool at the latest version, use `command@latest`: `[](#__codelineno-5-1) $ uvx ruff@latest check` The `--from` option can also be used to specify package versions, as above: `[](#__codelineno-6-1) $ uvx --from 'ruff==0.3.0' ruff check` Or, to constrain to a range of versions: `[](#__codelineno-7-1) $ 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](#requesting-extras) ---------------------------------------- The `--from` option can be used to run a tool with extras: `[](#__codelineno-8-1) $ uvx --from 'mypy[faster-cache,reports]' mypy --xml-report mypy_report` This can also be combined with version selection: `[](#__codelineno-9-1) $ uvx --from 'mypy[faster-cache,reports]==1.13.0' mypy --xml-report mypy_report` [Requesting different sources](#requesting-different-sources) -------------------------------------------------------------- The `--from` option can also be used to install from alternative sources. For example, to pull from git: `[](#__codelineno-10-1) $ uvx --from git+https://github.com/httpie/cli httpie` You can also pull the latest commit from a specific named branch: `[](#__codelineno-11-1) $ uvx --from git+https://github.com/httpie/cli@master httpie` Or pull a specific tag: `[](#__codelineno-12-1) $ uvx --from git+https://github.com/httpie/[[email protected]](/cdn-cgi/l/email-protection) httpie` Or even a specific commit: `[](#__codelineno-13-1) $ uvx --from git+https://github.com/httpie/cli@2843b87 httpie` [Commands with plugins](#commands-with-plugins) ------------------------------------------------ Additional dependencies can be included, e.g., to include `mkdocs-material` when running `mkdocs`: `[](#__codelineno-14-1) $ uvx --with mkdocs-material mkdocs --help` [Installing tools](#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`: `[](#__codelineno-15-1) $ 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: `[](#__codelineno-16-1) $ 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: `[](#__codelineno-17-1) $ 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: `[](#__codelineno-18-1) $ uv tool install httpie` Additionally, package versions can be included without `--from`: `[](#__codelineno-19-1) $ uv tool install 'httpie>0.1.0'` And, similarly, for package sources: `[](#__codelineno-20-1) $ uv tool install git+https://github.com/httpie/cli` As with `uvx`, installations can include additional packages: `[](#__codelineno-21-1) $ uv tool install mkdocs --with mkdocs-material` [Upgrading tools](#upgrading-tools) ------------------------------------ To upgrade a tool, use `uv tool upgrade`: `[](#__codelineno-22-1) $ 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`: `[](#__codelineno-23-1) $ uv tool install ruff>=0.4` To instead upgrade all tools: `[](#__codelineno-24-1) $ uv tool upgrade --all` [Requesting Python versions](#requesting-python-versions) ---------------------------------------------------------- By default, uv will use your default Python interpreter (the first it finds) when 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: `[](#__codelineno-25-1) $ uvx --python 3.10 ruff` Or, when installing a tool: `[](#__codelineno-26-1) $ uv tool install --python 3.10 ruff` Or, when upgrading a tool: `[](#__codelineno-27-1) $ uv tool upgrade --python 3.10 ruff` For more details on requesting Python versions, see the [Python version](../../concepts/python-versions/#requesting-a-version) concept page.. [Legacy Windows Scripts](#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)\\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. `[](#__codelineno-28-1) $ 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. `[](#__codelineno-29-1) $ uv tool run --from nuitka==2.6.7 nuitka --version` [Next steps](#next-steps) -------------------------- To learn more about managing tools with uv, see the [Tools concept](../../concepts/tools/) page and the [command reference](../../reference/cli/#uv-tool) . Or, read on to learn how to [work on projects](../projects/) . Back to top --- # Running scripts | uv [Running scripts](#running-scripts) ==================================== A Python script is a file intended for standalone execution, e.g., with `python