# Setting Up Custom PyTorch Indexes for Nightly or Bleeding‑Edge Builds with uv

> Easily install custom PyTorch indexes for nightly or bleeding-edge builds with uv. Configure pyproject.toml to declaratively manage hardware-specific package variants.

- Repository: [Th3Unknovvn/uv-install-torch](https://github.com/baonguyen6742/uv-install-torch)
- Tags: tutorial
- Published: 2026-02-26

---

**Configure uv's `[tool.uv.sources]` and `[tool.uv.index]` sections in [`pyproject.toml`](https://github.com/baonguyen6742/uv-install-torch/blob/main/pyproject.toml) to declaratively install PyTorch from custom CPU or CUDA package indexes, selecting hardware-specific variants through mutually exclusive optional extras.**

Setting up custom PyTorch indexes for nightly or bleeding‑edge builds with uv eliminates manual wheel management and complex pip installation commands. The `baonguyen6742/uv-install-torch` repository demonstrates a fully declarative approach that uses static configuration to resolve PyTorch wheels from the official custom indexes based on your selected hardware target.

## Configuring Custom Indexes in pyproject.toml

The entire workflow centers on **[`pyproject.toml`](https://github.com/baonguyen6742/uv-install-torch/blob/main/pyproject.toml)**, where project metadata, optional dependencies, and index definitions coalesce. This file replaces traditional installation scripts with a reproducible configuration that uv consumes to resolve and lock dependencies.

### Declaring Optional Dependencies for CPU and CUDA

Define two mutually exclusive extras under `[project.optional-dependencies]` to represent the CPU‑only and CUDA‑enabled variants. Both extras declare identical package versions, but uv routes them to different indexes based on subsequent source mappings.

```toml
[project.optional-dependencies]
cpu = ["torch==2.4.1", "torchvision==0.19.1", "torchaudio==2.4.1"]
cu124 = ["torch==2.4.1", "torchvision==0.19.1", "torchaudio==2.4.1"]

```

### Mapping Package Sources to Specific Indexes

The **`[tool.uv.sources]`** section creates conditional logic that binds each extra to its corresponding PyTorch index. When uv resolves dependencies, it selects the URL based on which extra is active during synchronization.

```toml
[tool.uv.sources]
torch = [
  { index = "pytorch-cpu", extra = "cpu" },
  { index = "pytorch-cu124", extra = "cu124" },
]

```

### Defining Index URLs and Conflict Resolution

Declare the actual PyTorch repository URLs under **`[[tool.uv.index]]`**. To prevent uv from attempting to install both CPU and CUDA wheels simultaneously—an impossible state since they provide the same package names—explicitly declare them as conflicting using the `conflicts` array.

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

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

[tool.uv]
conflicts = [[{ extra = "cpu" }, { extra = "cu124" }]]

```

## Installing PyTorch from Custom Indexes

With the configuration in place, use **`uv sync`** with the appropriate **`--extra`** flag to install your desired variant. This command resolves the dependency graph against the specified index and generates or updates `uv.lock` for reproducibility.

Install the CUDA 12.4 build:

```bash
uv sync --extra cu124

```

Install the CPU-only build:

```bash
uv sync --extra cpu

```

## Managing Cache and Environment State

When switching between indexes or troubleshooting resolution failures, clear uv's cache to purge stale metadata about available wheels. This forces uv to re-query the custom indexes on the next synchronization.

Clear the PyTorch-specific cache and reinstall:

```bash
uv cache clean torch
uv sync --extra cu124

```

For a complete environment reset—necessary when switching between radically different PyTorch builds or recovering from resolution corruption—remove the virtual environment and lock file before re-syncing:

```bash
rm -rf .venv uv.lock
uv sync --extra cu124

```

## Verifying the Installation

The repository includes **[`main.py`](https://github.com/baonguyen6742/uv-install-torch/blob/main/main.py)**, a minimal verification script that imports the installed libraries and inspects GPU availability. Execute it using **`uv run`** to confirm that the correct wheels are active without manually activating the virtual environment.

```bash
uv run main.py

```

The script calls `torch.cuda.is_available()` to validate that the CUDA build detects the GPU, or confirms the CPU-only configuration when `False`.

## Summary

- **Declarative configuration** in [`pyproject.toml`](https://github.com/baonguyen6742/uv-install-torch/blob/main/pyproject.toml) replaces imperative installation scripts for managing custom PyTorch indexes.
- **Mutually exclusive extras** (`cpu` and `cu124`) map to distinct PyTorch wheel repositories via `[tool.uv.sources]`.
- **Explicit conflict declaration** prevents the resolver from attempting to install incompatible CPU and CUDA variants simultaneously.
- **Index-specific caching** via `uv cache clean torch` resolves metadata conflicts when switching between stable and nightly builds.
- **Environment verification** through `uv run main.py` provides immediate feedback on whether GPU acceleration is active.

## Frequently Asked Questions

### How do I switch from a CUDA build to a CPU build?

Clear the uv cache to eliminate stale resolution metadata, then synchronize with the CPU extra. The `conflicts` array in [`pyproject.toml`](https://github.com/baonguyen6742/uv-install-torch/blob/main/pyproject.toml) ensures uv uninstalls the CUDA variant before installing the CPU wheels.

```bash
uv cache clean torch
uv sync --extra cpu

```

### Can I configure multiple CUDA versions simultaneously?

While you can define additional extras for other CUDA versions (e.g., `cu118`) in `[project.optional-dependencies]`, the repository implements **strict mutual exclusivity** via the `conflicts` setting. Supporting multiple simultaneous CUDA versions requires separate virtual environments or removing the conflicts constraint and manually managing the resolution graph.

### Why does uv require explicit conflict declaration for PyTorch extras?

Without the **`conflicts = [[{ extra = "cpu" }, { extra = "cu124" }]]`** configuration, uv's resolver might attempt to satisfy both extras if transitive dependencies request them, creating an impossible resolution state where both CPU and CUDA wheels of the same package version are required. Explicit conflicts enforce a single variant per environment.

### How do I install a specific nightly build instead of the stable versions shown?

Update the version pins in `[project.optional-dependencies]` to reference the specific nightly wheel (e.g., `torch==2.5.0.dev20240815+cu124`) and change the index URLs in `[[tool.uv.index]]` to point to the nightly repositories (e.g., `https://download.pytorch.org/whl/nightly/cu124`). The `[tool.uv.sources]` mapping logic remains identical regardless of whether the index serves stable or bleeding‑edge releases.