# Resolving Conflicts Between Optional Dependencies (CPU vs cu124 Extras) with uv

> Learn how to resolve CPU vs cu124 PyTorch dependency conflicts with uv using the [tool.uv.conflicts] table in pyproject.toml. Prevent incompatible installations.

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

---

**Use the `[tool.uv.conflicts]` table in [`pyproject.toml`](https://github.com/baonguyen6742/uv-install-torch/blob/main/pyproject.toml) to declare mutually exclusive extras like `cpu` and `cu124`, preventing `uv` from installing incompatible PyTorch wheels simultaneously.**

The `baonguyen6742/uv-install-torch` repository demonstrates a robust pattern for resolving conflicts between optional dependencies when distributing PyTorch packages with `uv`. By leveraging `uv`'s native conflict resolution and index management, developers can offer distinct CPU-only and CUDA-enabled installation paths while ensuring users cannot accidentally mix incompatible binaries.

## Configuring Mutually Exclusive Extras in pyproject.toml

The solution centers on three specific sections within [`pyproject.toml`](https://github.com/baonguyen6742/uv-install-torch/blob/main/pyproject.toml) that work together to present alternative installation paths while enforcing exclusivity.

### Declaring Optional Dependencies

The `[project.optional-dependencies]` section defines two extras: `cpu` and `cu124`. Each extra lists identical packages—`torch`, `torchvision`, and `torchaudio`—but relies on subsequent configuration to resolve them against different wheel indexes.

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

```

### Enforcing Conflicts with [tool.uv.conflicts]

The critical mechanism preventing simultaneous installation resides in the `[tool.uv.conflicts]` table. According to the source code in [`pyproject.toml`](https://github.com/baonguyen6742/uv-install-torch/blob/main/pyproject.toml), the following declaration instructs `uv` to treat these extras as mutually exclusive:

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

```

When a user attempts to install both extras simultaneously, `uv` reads this configuration and aborts immediately with a clear error message:

```bash
uv pip install .[cpu,cu124]

```

```

error: The extras "cpu" and "cu124" conflict with each other.

```

This prevents the runtime import errors and binary mismatches that would occur if CPU and CUDA wheels were mixed in the same environment.

### Mapping Package Sources to Specific Indexes

The `[tool.uv.sources]` section maps each extra to its respective PyTorch repository index. The `cpu` extra pulls wheels from `https://download.pytorch.org/whl/cpu`, while `cu124` targets `https://download.pytorch.org/whl/cu124`. This configuration ensures `uv` fetches the correct binaries without requiring manual URL handling or environment variables.

## Installing PyTorch CPU vs CUDA-124 Variants

Depending on hardware availability, users select exactly one extra during installation.

**Install the CPU-only variant:**

```bash
uv pip install .[cpu]

```

**Install the CUDA-124 variant:**

```bash
uv pip install .[cu124]

```

**Install only core dependencies (no PyTorch):**

```bash
uv pip install .

```

This installs only the packages listed under `[project.dependencies]` (such as `numpy` or `opencv-python`), omitting the heavy PyTorch stack entirely.

## Verifying the Installation with main.py

The repository includes [`main.py`](https://github.com/baonguyen6742/uv-install-torch/blob/main/main.py) to validate that the correct wheel variant is active. After installation, running the script imports the packages and performs a sanity check:

```bash
python main.py

```

For CUDA installations, the output confirms GPU availability:

```

torch.cuda.is_available True
Device 0 :  name='NVIDIA GeForce RTX 3080', total_memory=...

```

For CPU installations, `torch.cuda.is_available` returns `False`, verifying that the CPU-only wheels from the `pytorch-cpu` index are in use.

## Summary

- **[tool.uv.conflicts]** in [`pyproject.toml`](https://github.com/baonguyen6742/uv-install-torch/blob/main/pyproject.toml) explicitly declares that `cpu` and `cu124` extras cannot coexist, preventing incompatible PyTorch installations.
- **[tool.uv.sources]** directs `uv` to fetch wheels from distinct PyTorch indexes (`pytorch-cpu` vs `pytorch-cu124`) based on the selected extra.
- **Installation commands** use bracket notation (`.[cpu]` or `.[cu124]`) to select the appropriate binary variant.
- **[`main.py`](https://github.com/baonguyen6742/uv-install-torch/blob/main/main.py)** provides runtime verification that the correct wheels (CPU or CUDA) are installed and functional.

## Frequently Asked Questions

### What happens if I try to install both cpu and cu124 extras simultaneously?

`uv` detects the conflict defined in `[tool.uv.conflicts]` and aborts the installation with the error: `error: The extras "cpu" and "cu124" conflict with each other.` This prevents the package manager from creating an environment with mixed CPU and CUDA binaries that would cause runtime failures.

### How does uv know which PyTorch index to use for each extra?

The `[tool.uv.sources]` table in [`pyproject.toml`](https://github.com/baonguyen6742/uv-install-torch/blob/main/pyproject.toml) maps the `torch`, `torchvision`, and `torchaudio` packages to specific indexes based on the active extra. When you specify `.[cpu]`, `uv` queries the `pytorch-cpu` index (`https://download.pytorch.org/whl/cpu`); for `.[cu124]`, it queries the `pytorch-cu124` index.

### Can I use this pattern for other mutually exclusive dependencies?

Yes. The `conflicts` table supports any optional extras defined in your project. You can declare multiple conflict groups or create complex exclusion rules (for example, `tf-cpu` vs `tf-gpu`) using the same `[[{ extra = "name1" }, { extra = "name2" }]]` syntax demonstrated in `baonguyen6742/uv-install-torch`.

### Does this conflict resolution work with uv sync as well as uv pip install?

Yes. The `[tool.uv.conflicts]` configuration is respected across all `uv` commands that resolve dependencies, including `uv sync` and `uv run`. Whether installing from a [`pyproject.toml`](https://github.com/baonguyen6742/uv-install-torch/blob/main/pyproject.toml) directly or locking dependencies into a `uv.lock` file, `uv` will enforce that conflicting extras cannot be selected together.