# How to Build Read the Docs with uv


If your docs already build on Read the Docs, you can now switch `.readthedocs.yaml` to native [uv](https://pydevtools.com/handbook/reference/uv.md) support instead of maintaining a hand-rolled `build.jobs` override. Read the Docs added this support on April 21, 2026. The two supported paths are `uv sync` with a `docs` dependency group, and `uv pip install` with a requirements file.

## Define a docs dependency group

If your project already has a [`pyproject.toml`](https://pydevtools.com/handbook/reference/pyproject.toml.md), declare a dependency group for the documentation toolchain. Groups are the [PEP 735](https://pydevtools.com/handbook/explanation/what-is-pep-735.md) standard place to keep development-only dependencies out of what your users install:

```toml {filename="pyproject.toml"}
[dependency-groups]
docs = [
    "sphinx>=8.1",
    "furo>=2024.8",
    "myst-parser>=4.0",
]
```

Pin the versions you actually build with. Dependency groups never ship to PyPI, so they exist only for local and CI installs (see [the dependency-groups explainer](https://pydevtools.com/handbook/explanation/understanding-dependency-groups-in-uv.md) for the full model).

## Wire up .readthedocs.yaml to use uv sync

Create `.readthedocs.yaml` at the repo root with `method: uv` and `command: sync`:

```yaml {filename=".readthedocs.yaml"}
version: 2

build:
  os: ubuntu-24.04
  tools:
    python: "3.13"

python:
  install:
    - method: uv
      command: sync
      groups:
        - docs
```

Read the Docs runs `uv sync` against your `pyproject.toml` and pulls in the `docs` group alongside the project's main dependencies. If a `uv.lock` file is present in the repo, uv installs from it; otherwise it resolves fresh.

The `groups` key takes either a list of group names or the string `all`. Use `all` to install every declared group:

```yaml
python:
  install:
    - method: uv
      command: sync
      groups: all
```

## Pin Python with build.tools.python

Set `build.tools.python` to an explicit version that satisfies your project's `requires-python`, such as `"3.13"` or `"3.14"`. Avoid `"3"` unless you're willing to let doc builds float to the latest 3.x available on Read the Docs.

## Commit uv.lock for reproducible doc builds

A single `uv.lock` covers both the application or library and the docs build. Commit it to version control and Read the Docs installs the exact resolved versions on every build.

```console
$ git add uv.lock
$ git commit -m "Lock dependencies"
```

Without `uv.lock`, every build re-resolves and may pull in newer compatible versions of Sphinx, your theme, or any plugin. That works, but a docs build that succeeded yesterday can fail today on a transitive upgrade. See [How to use a uv lockfile for reproducible Python environments](https://pydevtools.com/handbook/how-to/how-to-use-a-uv-lockfile-for-reproducible-python-environments.md) for the full mechanics of `uv lock` and `uv sync --locked`.

## Install from a requirements file instead

Projects that aren't on `pyproject.toml` yet can still use uv on Read the Docs by switching `command` to `pip`:

```yaml {filename=".readthedocs.yaml"}
version: 2

build:
  os: ubuntu-24.04
  tools:
    python: "3.13"

python:
  install:
    - method: uv
      command: pip
      requirements: docs/requirements.txt
```

Read the Docs runs `uv pip install -r docs/requirements.txt`. Use `path:` instead of `requirements:` to install the package itself with optional extras:

```yaml
python:
  install:
    - method: uv
      command: pip
      path: .
      extras:
        - docs
```

That maps to `uv pip install .[docs]`.

## Avoid the two uv-mode pitfalls

Two rules trip people up on the first migration:

1. Only one `python.install` entry is allowed when `method: uv`. The legacy pip method lets you stack a requirements install and a package install. The uv method does not. Fold everything into a single `sync` (with groups or extras) or a single `pip` invocation.
2. `sync` and `pip` accept different keys. `groups` belongs to `command: sync` and is rejected under `command: pip`. `requirements` belongs to `command: pip` and is rejected under `command: sync`. Pick the command that matches the input you have (a `pyproject.toml` for `sync`, a `requirements.txt` for `pip`) and use only that command's keys.

## Reach for build.jobs when uv-mode is too narrow

Native `method: uv` covers the common cases but does not surface every uv flag. Workflows that need `--locked`, `--frozen`, `--no-dev`, or a multi-step install have to drop down to `build.jobs` and call uv directly. See [Read the Docs build customization](https://docs.readthedocs.com/platform/stable/build-customization.html) for the escape hatch and stay on `python.install` for everything else.

## Learn more

- [uv: A Complete Guide](https://pydevtools.com/handbook/explanation/uv-complete-guide.md) covers what uv does, how fast it is, the core workflows, and recent releases.
- [How to Set Up Documentation for a Python Package with Sphinx or MkDocs](https://pydevtools.com/handbook/how-to/how-to-set-up-documentation-for-a-python-package.md) scaffolds the source tree this configuration builds.
- [Read the Docs: uv is now supported natively](https://about.readthedocs.com/blog/2026/04/uv-native-support/) is the original announcement.
- [Configuration file reference: python.install](https://docs.readthedocs.com/platform/stable/config-file/v2.html#uv) lists every key the parser accepts.
- [Build customization](https://docs.readthedocs.com/platform/stable/build-customization.html) covers the `build.jobs` escape hatch.
- [uv sync documentation](https://docs.astral.sh/uv/reference/cli/#uv-sync) documents the underlying command.
