Automating Documentation Builds and Deployment with GitHub Actions and GitHub Pages

Picture this: you’ve just fixed a critical bug in your Python library, updated all the docstrings, and added a new tutorial. You’re ready to push the changes, but then you remember… you need to rebuild and deploy the documentation. Again. Manually. For the third time today.

If this sounds familiar, you’re not alone. I’ve been there, and I’ve learned that automating documentation deployment isn’t just a nice-to-have - it’s essential for maintaining your sanity and ensuring your docs stay in sync with your code. In this post, I’ll show you how to set up GitHub Actions workflows that automatically build your Sphinx docs and deploy them to GitHub Pages every time you push to master.

Before We Start

You’ll need:

  • A GitHub repository with your Sphinx documentation
  • Basic familiarity with GitHub Actions (but don’t worry if you’re new to it)
  • GitHub Pages enabled for your repository

Setting Up GitHub Pages

First things first, let’s get GitHub Pages configured. Head over to your repository’s settings and look for the “Pages” section. You have two main options:

  1. Deploy from a gh-pages branch (my preferred approach)
  2. Deploy from the /docs folder on your main branch

I recommend the gh-pages branch approach because it keeps your documentation builds separate from your source code. We’ll set up our workflow to automatically push the built HTML files to this branch.

Creating Your Documentation Workflows

We’ll create two GitHub Actions workflows:

  1. One for deploying documentation when pushing to master
  2. Another for validating documentation builds on pull requests

Let’s create these files in your .github/workflows/ directory.

The Deployment Workflow

Create .github/workflows/docs.yml:

name: "Master Docs Publication"

on:
  push:
    branches: [ master ]

jobs:
  docs:
    runs-on: ubuntu-latest
    steps:
    - name: Clone
      uses: actions/checkout@v1

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.10'

    - name: Build Docs
      uses: ammaraskar/sphinx-action@master
      with:
        docs-folder: "./docs/"

    - name: Deploy Docs
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: "./docs/build/html/"

The Pull Request Validation Workflow

Create .github/workflows/test-docs-build.yml:

name: "Pull Request Docs Check"

on:
- pull_request

jobs:
  docs:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v1

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.10'

    - name: Build Docs
      uses: ammaraskar/sphinx-action@master
      with:
        docs-folder: "docs/"

Understanding the Workflows

Let’s break down what these workflows do:

  1. The Deployment Workflow (docs.yml):

    • Triggers when you push to the master branch
    • Clones your repository
    • Sets up Python 3.10
    • Uses uv (a fast Python package installer) for dependency management
    • Builds your documentation using sphinx-action
    • Deploys the built docs to GitHub Pages
  2. The PR Validation Workflow (test-docs-build.yml):

    • Triggers on pull requests
    • Does everything the deployment workflow does except the deployment step
    • Acts as a quality check to catch documentation build errors before they hit master

Treating Warnings as Errors

In many cases, you’ll want to ensure your documentation is pristine by treating warnings as errors. This helps catch issues like broken links, invalid cross-references, or missing docstrings early. To enable this in your workflow, modify the sphinx-action configuration:

- name: Build Docs
  uses: ammaraskar/sphinx-action@master
  with:
    docs-folder: "docs/"
    build-command: "sphinx-build -W -b html . build/html"  # -W flag treats warnings as errors

This configuration will fail the build if any warnings are encountered, ensuring your documentation stays clean and accurate.

Setting Up Custom Domains

While GitHub Pages provides a default domain (username.github.io/repo), you might want to use a custom domain for your documentation. Here’s how to set it up:

  1. Configure DNS: First, set up your DNS records:

    • For apex domains (example.com): Create an A record pointing to GitHub’s IP addresses
    • For subdomains (docs.example.com): Create a CNAME record pointing to your GitHub Pages domain
  2. Add CNAME File: Create a CNAME file in your documentation source that will be built and deployed. Add this to your docs/source directory:

    echo "docs.example.com" > docs/source/CNAME
  3. Update Sphinx Configuration: Modify your docs/conf.py to copy the CNAME file into the build output:

    # At the end of conf.py
    
    # Copy CNAME file to output directory
    html_extra_path = ['CNAME']

    This tells Sphinx to copy the CNAME file directly into the HTML build output directory, ensuring it’s included in your documentation deployment.

  4. Enable in GitHub: In your repository settings under Pages, enter your custom domain and ensure “Enforce HTTPS” is checked.

Remember that DNS changes can take up to 48 hours to propagate, though they often take effect much sooner.

Project Setup Requirements

To use these workflows, your project should have:

  1. A docs/ directory at the root of your repository containing your Sphinx documentation
  2. A requirements.txt file in your docs/ directory listing all documentation dependencies. This is required by the sphinx-action. For example:
    sphinx>=7.0.0
    sphinx-rtd-theme>=1.3.0
    myst-parser>=2.0.0  # If you use Markdown
    sphinx-autodoc-typehints>=1.25.0  # For better type hints

Making It Your Own

While these workflows will work out of the box for many projects, here are some common customizations:

  1. Different Python Version: Change the python-version in the “Set up Python” step:

    python-version: '3.11'  # or whatever version you need
  2. Different Branch Name: If you use ‘main’ instead of ‘master’:

    branches: [ main ]
  3. Custom Documentation Path: If your docs are in a different location:

    docs-folder: "path/to/your/docs/"

The Real Benefits

This two-workflow setup gives you:

  1. Automatic documentation deployment on merges to master
  2. Early warning system for documentation issues in PRs
  3. Fast dependency installation with uv
  4. Clean separation between validation and deployment

One Last Tip

Add badges to your README to show your documentation status:

[![Docs Deployment](https://github.com/username/repo/actions/workflows/docs.yml/badge.svg)](https://username.github.io/repo/)
[![Docs Check](https://github.com/username/repo/actions/workflows/test-docs-build.yml/badge.svg)](https://github.com/username/repo/actions)

Remember: good documentation is a continuous process, not a one-time task. By automating the deployment and validation, you’re free to focus on what matters - writing great docs and great code.

Subscribe to the Newsletter

Get the latest posts and insights delivered straight to your inbox.