Skip to main content
By default, uv uses the Python Package Index (PyPI) for dependency resolution and package installation. However, uv can be configured to use other package indexes, including private indexes.

Defining an Index

To include an additional index when resolving dependencies, add a [[tool.uv.index]] entry to your pyproject.toml:
pyproject.toml
[[tool.uv.index]]
# Optional name for the index
name = "pytorch"
# Required URL for the index
url = "https://download.pytorch.org/whl/cpu"
name
string
Optional identifier for the index. Must contain only alphanumeric characters, dashes, underscores, and periods (valid ASCII).
url
string
required
The URL of the package index (Simple API endpoint).

Command-Line Usage

Indexes can also be provided via command line or environment variables:
# Command line with name
uv lock --index pytorch=https://download.pytorch.org/whl/cpu

# Environment variable
export UV_INDEX="pytorch=https://download.pytorch.org/whl/cpu"
uv lock

Index Priority

Indexes are prioritized in the order they’re defined:
  1. Command-line indexes (highest priority)
  2. Configuration file indexes (in order of appearance)
  3. Default index (lowest priority)
The first index listed is the first consulted when resolving dependencies.

Default Index

By default, uv includes PyPI as the “default” index (used when a package is not found on other indexes). To replace PyPI with a different default index:
pyproject.toml
[[tool.uv.index]]
name = "private-pypi"
url = "https://private.example.com/simple"
default = true
default
boolean
default:false
Mark this index as the default. The default index is always treated as lowest priority, regardless of position.
Command-line equivalent:
uv lock --default-index https://private.example.com/simple

# Or via environment variable
export UV_DEFAULT_INDEX="https://private.example.com/simple"

Pinning Packages to an Index

Pin a package to a specific index using tool.uv.sources:
pyproject.toml
[tool.uv.sources]
torch = { index = "pytorch" }

[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
This ensures torch is always installed from the pytorch index.

Platform-Specific Indexes

Use environment markers to select indexes by platform:
pyproject.toml
[project]
dependencies = ["torch"]

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

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

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

Explicit Indexes

Mark an index as explicit = true to prevent packages from being installed from it unless explicitly pinned:
pyproject.toml
[tool.uv.sources]
torch = { index = "pytorch" }

[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
explicit = true
explicit
boolean
default:false
When true, packages can only be installed from this index if explicitly pinned via tool.uv.sources.
Named indexes referenced via tool.uv.sources must be defined within the project’s pyproject.toml. Indexes provided via command-line, environment variables, or user-level configuration will not be recognized.

Index Search Strategies

Control how uv searches across multiple indexes using the --index-strategy option or UV_INDEX_STRATEGY environment variable:

first-index (Default)

Search for each package across all indexes, limiting candidate versions to those present in the first index that contains the package.
uv sync --index-strategy first-index
This prevents “dependency confusion” attacks where an attacker publishes a malicious package on PyPI with the same name as an internal package.

unsafe-first-match

Search across all indexes, but prefer the first index with a compatible version, even if newer versions are available on other indexes.
uv sync --index-strategy unsafe-first-match

unsafe-best-match

Search across all indexes and select the best version from the combined set of candidate versions (closest to pip’s behavior).
uv sync --index-strategy unsafe-best-match
The unsafe-best-match strategy exposes users to “dependency confusion” attacks. See the torchtriton attack for an example.

Authentication

Most private package indexes require authentication. See the Authentication documentation for detailed information.

Credentials via Environment Variables

Provide credentials without storing them in plaintext:
pyproject.toml
[[tool.uv.index]]
name = "internal-proxy"
url = "https://example.com/simple"
export UV_INDEX_INTERNAL_PROXY_USERNAME=public
export UV_INDEX_INTERNAL_PROXY_PASSWORD=koala
The environment variable name follows the pattern UV_INDEX_<NORMALIZED_NAME>_USERNAME and UV_INDEX_<NORMALIZED_NAME>_PASSWORD, where <NORMALIZED_NAME> is the uppercase index name with non-alphanumeric characters replaced by underscores.

Credentials in URL

Alternatively, embed credentials directly in the URL:
pyproject.toml
[[tool.uv.index]]
name = "internal"
url = "https://public:[email protected]/simple"
Credentials are never stored in the uv.lock file. uv must have access to authenticated URLs at installation time.

Authentication Behavior

Control when uv searches for credentials:
authenticate
string
default:"auto"
Controls credential discovery behavior:
  • "auto": Attempt unauthenticated request first, search for credentials on failure
  • "always": Always search for credentials before making requests (required for some indexes like GitLab)
  • "never": Never search for credentials (prevents credential leaking)
pyproject.toml
[[tool.uv.index]]
name = "gitlab"
url = "https://gitlab.example.com/api/v4/projects/123/packages/pypi/simple"
authenticate = "always"
If a username is set, uv will search for credentials before making an unauthenticated request, regardless of the authenticate setting.

Error Handling

Ignored Error Codes

When using the first-index strategy, uv stops searching across indexes on HTTP 401 or 403 errors. Customize this behavior:
pyproject.toml
[[tool.uv.index]]
name = "private-index"
url = "https://private-index.com/simple"
authenticate = "always"
ignore-error-codes = [403]
ignore-error-codes
array
List of HTTP status codes to ignore when searching across indexes. uv will continue to the next index if these codes are encountered.
uv always continues searching on 404 Not Found errors. This cannot be overridden.

Cache Control

Customize caching behavior for an index:
pyproject.toml
[[tool.uv.index]]
name = "example"
url = "https://example.com/simple"
cache-control = { api = "max-age=600", files = "max-age=365000000, immutable" }
cache-control
object
Override HTTP cache control headers:
  • api: Controls caching for Simple API requests (package metadata)
  • files: Controls caching for artifact downloads (wheels and source distributions)
By default, uv respects the cache control headers provided by the index. PyPI uses:
  • Metadata: max-age=600 (10 minutes)
  • Artifacts: max-age=365000000, immutable (indefinite)
Force revalidation:
pyproject.toml
[[tool.uv.index]]
name = "example"
url = "https://example.com/simple"
cache-control = { api = "no-cache" }

Flat Indexes

In addition to PyPI-style registries (PEP 503), uv supports “flat” indexes (local directories or HTML pages with flat lists of wheels and source distributions):
pyproject.toml
[[tool.uv.index]]
name = "local-packages"
url = "/path/to/directory"
format = "flat"
format
string
default:"simple"
Index format:
  • "simple": PyPI-style registry (PEP 503 Simple Repository API)
  • "flat": Flat index (equivalent to pip’s --find-links)
Flat indexes support the same features as Simple API indexes, including explicit = true and pinning via tool.uv.sources.

Legacy pip Compatibility

For compatibility with pip, uv supports --index-url and --extra-index-url:
# pip-style (legacy)
uv pip install --index-url https://test.pypi.org/simple package-name

# uv-style (recommended)
uv pip install --default-index https://test.pypi.org/simple package-name
Mapping:
  • --index-url--default-index (sets default index)
  • --extra-index-url--index (adds additional index)
These can be combined with [[tool.uv.index]] configuration and follow the same prioritization rules.

Examples

Multiple Indexes with Priority

pyproject.toml
# PyTorch is checked first
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"

# Internal index is checked second
[[tool.uv.index]]
name = "internal"
url = "https://internal.example.com/simple"

# Custom default replaces PyPI (checked last)
[[tool.uv.index]]
name = "private-pypi"
url = "https://private.pypi.example.com/simple"
default = true

Private Registry with Authentication

pyproject.toml
[[tool.uv.index]]
name = "private"
url = "https://pypi.private.example.com/simple"
authenticate = "always"
ignore-error-codes = [403]
cache-control = { api = "max-age=600" }
export UV_INDEX_PRIVATE_USERNAME=myuser
export UV_INDEX_PRIVATE_PASSWORD=mytoken
uv sync

Explicit Index for Specific Packages

pyproject.toml
[project]
dependencies = ["torch", "numpy"]

[tool.uv.sources]
# Only torch comes from pytorch index
torch = { index = "pytorch" }

# PyTorch index is only used for explicitly pinned packages
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
explicit = true

# All other packages come from PyPI (default)

Build docs developers (and LLMs) love