ReadTheDocs v2 Configuration: Pinning Builds, Adding Formats, and Migrating from Legacy YAML
Learn how to migrate to ReadTheDocs v2 config, pin build images and Python versions, add PDF/EPUB output, use conda for system dependencies, and avoid common pitfalls like legacy file conflicts and missing directory changes.
12 Jun 2026, 22:26 UTC

Why the v2 config matters
The single most useful change you can make today is to add a .readthedocs.yaml file with version: 2 at the top. This pins the build image, Python interpreter, and output formats so every build — local or on ReadTheDocs — produces identical artifacts. The legacy .readthedocs.yml is still parsed for backward compatibility, but mixing the two files creates undefined precedence and should be avoided.
Worked example: a minimal Sphinx project
Place the following file at the repository root (or in a subdirectory if you run a monorepo). It selects Ubuntu 22.04, Python 3.11, installs dependencies from docs/requirements.txt, runs Sphinx, and emits HTML, PDF, and EPUB.
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.11"
jobs:
post_create_environment:
- pip install -r docs/requirements.txt
post_install:
- cd docs && sphinx-build -b html . _build/html
formats:
- pdf
- epub
Key fields:
- build.os – chooses the build image (
ubuntu-22.04orubuntu-20.04). - build.tools.python – pins the interpreter; major.minor (e.g.,
3.11) or a Miniconda specifier (miniconda3-4.12.0). Omitting this defaults to the platform Python, which varies by image and breaks reproducibility. - build.jobs.post_create_environment – runs before the default
pip install -r requirements.txtfrom the repo root. Use it for system‑level setup or to install a private index. - build.jobs.post_install – runs after the root
pip install. If your docs live in a subdirectory,cdexplicitly (as shown) or invokepython -m pip install -r docs/requirements.txt. - formats – adds PDF and EPUB output; HTML is always built.
Using conda for system dependencies
When you need non‑Python packages (e.g., graphviz, texlive), prefer the conda: section over the legacy apt_packages list. Conda environments are reproducible locally and on the build servers.
build:
os: ubuntu-22.04
tools:
python: "3.11"
conda:
environment: docs/environment.yml
jobs:
post_install:
- cd docs && sphinx-build -b html . _build/html
formats:
- pdf
The referenced docs/environment.yml might contain:
name: docs-env
channels:
- conda-forge
dependencies:
- python=3.11
- sphinx
- graphviz
- texlive-core
- pip
- pip:
- -r requirements.txt
Run conda env create -f docs/environment.yml locally to verify the exact package set before pushing.
Environment variables injected at build time
ReadTheDocs injects several variables you can read in conf.py for version‑aware content:
READTHEDOCS_VERSION_NAME– the version label (branch name, tag, orlatest).READTHEDOCS_VERSION_TYPE–branch,tag, orexternal.READTHEDOCS_GIT_COMMIT_HASH– full SHA of the commit being built.READTHEDOCS– set toTrueonly during the build; not present in the hosted HTML.
Example conf.py snippet:
import os
version_name = os.environ.get('READTHEDOCS_VERSION_NAME', 'local')
html_title = f"My Project – {version_name}"
These variables are not available to client‑side JavaScript, so any runtime feature detection must be baked into the generated HTML.
Monorepo support
Each subproject gets its own .readthedocs.yaml placed in its directory. In the dashboard, set the project's Configuration file path to that file (e.g., subproject-a/.readthedocs.yaml). The dashboard accepts only one config file per project, so you create a separate ReadTheDocs project for each subproject.
Pull‑request previews
Previews are enabled by default for connected GitHub/GitLab/Bitbucket repos. On every push to a PR branch, ReadTheDocs builds the docs and serves them at a unique URL like https://--pr-42--myproject.readthedocs.io. These builds do not create permanent versions; they disappear when the PR is closed or merged.
Limits and common mistakes
Legacy file conflict
If both .readthedocs.yml and .readthedocs.yaml exist, ReadTheDocs may read either with undefined precedence. Delete the old .yml after migration.
Missing cd in post_install
The default pip install -r requirements.txt runs from the repository root. Forgetting to change directory causes Sphinx to look for conf.py in the wrong place and the build fails with conf.py not found.
PDF build timeout
The Ubuntu 22.04 image includes TeX Live, but large font packages or complex LaTeX can exceed the 15‑minute build timeout. Trim font packages or split the PDF build into a separate job if you hit this limit.
Changing build.os or build.tools.python
Any change to these fields invalidates the cached environment. The next build will be slower because it provisions a fresh container. Plan such changes during a low‑traffic window.
Environment variables not in hosted HTML
READTHEDOCS and the version variables exist only during the build. Do not write JavaScript that checks process.env.READTHEDOCS — it will always be undefined in the browser.
Verification checklist
- Create a test repo with the minimal v2 config above. Push to GitHub/GitLab.
- Import the repo on
readthedocs.org(or your self‑hosted instance). - Confirm v2 parsing – the build log should show lines like:
Using config file: .readthedocs.yaml Version: 2 - Check artifacts – after a successful build, open the version’s “Downloads” section; PDF and EPUB files must be present.
- Inspect injected vars – add
import os; print(os.environ.get('READTHEDOCS_VERSION_NAME'))toconf.py, rebuild, and verify the value appears in the build output. - Test PR preview – open a pull request; a unique preview URL should be generated and serve the built docs.
- Validate conda reproducibility – run
conda env create -f docs/environment.ymllocally, then compareconda listoutput with the build log’s conda package list.
Rollback note
Changing the config file does not mutate persistent state beyond the next build. If a new config breaks the build, revert the commit containing .readthedocs.yaml and push; the next build will use the previous working configuration.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.