Sphinx & reStructuredText Reference Portal

A living demonstration of Sphinx capabilities and reStructuredText mastery — from directives and roles to extensions, theming, and Docs-as-Code automation.

Authored by Oleh Shynkarenko, Senior Technical Writer



Overview

Sphinx is the industry-standard documentation engine for Python projects and increasingly adopted across the wider software engineering world. Paired with reStructuredText (reST), it provides a highly expressive, semantic markup language that compiles to HTML, PDF (via LaTeX), ePub, man pages, and more — all from a single plain-text source tree.

Note

reST predates Markdown and was designed specifically for technical documentation, with first-class support for cross-referencing, auto-generated indices, typed roles, and domain-specific markup that Markdown cannot match without heavy plugin ecosystems.

📄

Semantic Markup

reST encodes meaning, not just appearance. Roles like :py:class:, :ref:, and :term: make content machine-readable and automatically cross-referenceable.

🔌

Extension Ecosystem

Over 200 first- and third-party Sphinx extensions — autodoc, napoleon, mermaid, OpenAPI, nbsphinx — let you automate entire documentation pipelines from source code to published site.

🔀

Multi-Format Output

Build HTML, PDF, ePub, man pages, and texinfo from the same source tree using Sphinx builders — no extra conversion tools required.

⚙️

Docs-as-Code

Plain-text reST files live alongside code in Git. CI/CD pipelines (GitHub Actions, GitLab CI) build and publish docs automatically on every commit — no CMS needed.

reST Syntax Quick Reference

Inline Roles

reStructuredText expresses semantics through roles — inline markup prefixed with a colon. Unlike Markdown's visual-only emphasis, reST roles carry type information that Sphinx uses to generate a fully cross-referenced index:

:strong:`bold text`**bold text**
:emphasis:`italic text`*italic text*
:code:`inline_code()`         →  inline_code()
:command:`sphinx-build`       →  sphinx-build   (shell command)
:file:`/path/to/file.py`      →  /path/to/file.py
:guilabel:`OK`                →  OK             (UI label)
:kbd:`Ctrl+Shift+P`           →  Ctrl+Shift+P   (keyboard shortcut)
:menuselection:`File --> New`
:doc:`sdk/getting_started`    →  link to another page in this project
:ref:`home`                   →  link to a labelled anchor (any .rst file)
:py:class:`MyClass`           →  cross-reference to a Python class
:py:func:`my_module.helper`   →  cross-reference to a Python function
:envvar:`SPHINX_BUILD_DIR`    →  an environment variable
:rfc:`7519`                   →  link to RFC 7519 (JWT)
:pep:`517`                    →  link to PEP 517

Admonitions

Sphinx ships with a full palette of admonitions for callouts and alerts:

.. note::         General information worth highlighting
.. tip::          A helpful hint or shortcut
.. important::    Must-know information
.. warning::      Potential issues the reader should watch for
.. danger::       Destructive or irreversible consequences
.. caution::      Proceed with care
.. seealso::      Links to related topics
.. deprecated::   x.y  Feature removed in version x.y
.. versionadded:: x.y  Feature introduced in version x.y
.. versionchanged:: x.y Behaviour changed in version x.y

Tip

Combine admonitions with the .. only:: directive to show different callouts per builder — for example, a PDF-specific warning that would not apply to HTML readers.

Section Heading Hierarchy

reST headings are determined by underline (and optional overline) characters. The Python documentation convention, adopted by most Sphinx projects, is:

########
Part
########

========
Chapter
========

Section
-------

Subsection
~~~~~~~~~~

Sub-subsection
^^^^^^^^^^^^^^

Paragraph
"""""""""

Important

The character used is not fixed by the spec — Sphinx assigns levels based on first-occurrence order within each file. Consistency across a project is enforced by convention (or a linter such as rstcheck), not the parser.

Directives Deep-Dive

Anatomy of a Directive

Every Sphinx directive follows the same grammar. Understanding this structure is the key to reading and writing any directive — including custom ones:

# Anatomy of a reStructuredText directive

.. directive-name:: optional-argument
   :option-name: option-value
   :another-option: value
   :flag-option:   ← boolean flag, no value needed

   Body content — indented by 3 spaces (or 1 tab).
   This is the directive's content block. It may contain
   nested reST markup, including other directives.

Code Blocks

The .. code-block:: directive supports syntax highlighting via Pygments, which covers over 500 languages. Key options include :linenos:, :emphasize-lines:, :caption:, and :dedent::

conf.py — Sphinx project configuration
 1# conf.py
 2project = "SphinxDocs"
 3extensions = [
 4    "sphinx.ext.autodoc",       # Pull docstrings from Python source
 5    "sphinx.ext.napoleon",      # Google / NumPy docstring styles
 6    "sphinx.ext.viewcode",      # Add [source] links to API pages
 7    "sphinx.ext.intersphinx",   # Cross-project cross-references
 8    "sphinxcontrib.mermaid",    # Mermaid diagram support
 9    "sphinxcontrib.httpdomain", # HTTP API documentation
10]
11html_theme = "sphinx_rtd_theme"
12html_static_path = ["_static"]
13html_logo = "_static/logo.png"
14html_favicon = "_static/favicon.ico"
Sphinx build commands cheat-sheet
# Build HTML output
sphinx-build -b html source/ build/html

# Build PDF via LaTeX
sphinx-build -b latex source/ build/latex && make -C build/latex

# Auto-rebuild on save with live reload (requires sphinx-autobuild)
sphinx-autobuild source/ build/html --port 8080

# Check for broken external links
sphinx-build -b linkcheck source/ build/linkcheck

# Rebuild cleanly (ignore cached environment)
sphinx-build -E -b html source/ build/html

# Treat warnings as errors (for CI pipelines)
sphinx-build -W -b html source/ build/html

Includes and Substitutions

reST supports file includes and text substitutions — two powerful tools for maintaining a single source of truth across large documentation sets:

.. |product| replace:: SphinxDocs
.. |version| replace:: 2.4.1

The current version of |product| is |version|.

.. include:: shared/warning_banner.rst

.. literalinclude:: ../../src/my_module.py
   :language: python
   :lines: 10-35
   :caption: Source: my_module.py (lines 10–35)

Sphinx Extensions Comparison

Extension Purpose HTML PDF Complexity
sphinx.ext.autodoc Import & render Python docstrings automatically ✓ Yes ✓ Yes Low
sphinx.ext.napoleon Google / NumPy docstring styles ✓ Yes ✓ Yes Low
sphinx.ext.viewcode Add [source] links to API documentation pages ✓ Yes ✗ No Low
sphinx.ext.intersphinx Cross-project cross-references (e.g., link to Python stdlib) ✓ Yes ✓ Yes Medium
sphinxcontrib.mermaid Embed Mermaid diagrams as plain-text source ✓ Yes ~ Partial Low
sphinxcontrib.httpdomain Semantic markup for REST HTTP APIs ✓ Yes ✓ Yes Medium
nbsphinx Embed Jupyter Notebooks with live output ✓ Yes ~ Partial High
sphinx_rtd_theme Read the Docs HTML theme ✓ Yes ✗ No Low
sphinx.ext.coverage Report which Python symbols lack documentation ✓ Yes ✗ No Low

Tables in reStructuredText

reST provides three table syntaxes. The .. list-table:: directive is the most maintainable for Docs-as-Code workflows because it does not require manual ASCII alignment:

reST Table Syntax Comparison

Syntax

Readability

Best for

Tooling support

Grid table

Low (ASCII art)

Simple, narrow content

All editors; alignment tedious

Simple table

Medium

Column-aligned numeric data

All editors; no multi-line cells

list-table

High

Complex / multi-line cell content

Excellent — no manual alignment

csv-table

High

Data sourced from external CSV files

Excellent — reads live .csv files

Grid table example (ASCII art syntax)

+------------------+------------+---------------------+
| Header A         | Header B   | Header C            |
+==================+============+=====================+
| Row 1, Cell 1    | Cell 2     | Cell 3              |
+------------------+------------+---------------------+
| Row 2            | Cell 5     | Cell 6              |
+------------------+------------+---------------------+

Diagrams as Code with Mermaid

With sphinxcontrib-mermaid, diagrams live in version control as plain text — they are diff-able, reviewable, and never go stale because they live next to the content they describe.

Sphinx Build Pipeline

        flowchart LR
  A["Author writes .rst"] --> B{"sphinx-build"}
  B --> C["HTML output"]
  B --> D["PDF via LaTeX"]
  B --> E["ePub output"]
  C --> F["Read the Docs"]
  C --> G["GitHub Pages"]
  D --> H["Print / Download"]
    

Docs-as-Code CI/CD Sequence

        sequenceDiagram
  participant Dev as Developer
  participant Git as Git / GitHub
  participant CI  as GitHub Actions
  participant RTD as Read the Docs

  Dev->>Git: git push
  Git->>CI: Trigger workflow
  CI->>CI: sphinx-build -W -b html
  CI->>CI: sphinx-build -b linkcheck
  CI->>RTD: Deploy on success
  RTD-->>Dev: Build notification
    

Autodoc: Python API Documentation

sphinx.ext.autodoc pulls docstrings directly from Python source, keeping docs and code in sync automatically. Combine it with napoleon to support Google-style and NumPy-style docstrings:

src/auth.py — Python module with full Google-style docstring
class TokenManager:
    """Manage API authentication tokens.

    Supports Bearer token, API-key, and OAuth 2.0 client-credentials flows.
    Tokens are cached in-memory and refreshed automatically before expiry.

    Args:
        base_url (str): Root URL of the target API.
        timeout (int): Request timeout in seconds. Defaults to ``30``.

    Raises:
        AuthError: When credentials are invalid or have expired.

    Example:
        >>> mgr = TokenManager("https://api.example.com")
        >>> mgr.authenticate(client_id="abc", client_secret="xyz")
        >>> mgr.get_token()
        'eyJhbGciOiJSUzI1NiIs...'
    """

    def authenticate(self, client_id: str, client_secret: str) -> None:
        """Exchange client credentials for an access token (OAuth 2.0).

        Args:
            client_id (str): OAuth 2.0 client identifier.
            client_secret (str): OAuth 2.0 client secret.
        """
api/auth.rst — Rendering the class automatically with autodoc
.. autoclass:: auth.TokenManager
   :members:
   :undoc-members:
   :show-inheritance:
   :special-members: __init__

HTTP API Documentation

The sphinxcontrib-httpdomain extension adds a semantic HTTP domain so REST endpoints are documented with typed parameters, status codes, and request headers that Sphinx can cross-reference and index:

api/get_users.rst — Documenting a REST endpoint
.. http:get:: /api/v1/users/{user_id}

   Retrieve a single user by their unique identifier.

   :param user_id: Unique UUID of the user record.
   :type  user_id: uuid

   :reqheader Authorization: ``Bearer <token>``
   :reqheader Accept:        ``application/json``

   :statuscode 200: User record returned successfully.
   :statuscode 401: Missing or invalid authentication token.
   :statuscode 404: User not found.

   **Example response:**

   .. code-block:: json

      {
        "id":         "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "name":       "Oleh Shynkarenko",
        "role":       "admin",
        "created_at": "2026-04-30T09:00:00Z"
      }

Docs-as-Code Workflow

The following CI/CD workflow integrates Sphinx into a GitHub Actions pipeline — building, link-checking, and deploying documentation automatically on every merge to main:

.github/workflows/docs.yml — Production-grade GitHub Actions pipeline
 1name: Build & Deploy Docs
 2
 3on:
 4  push:
 5    branches: [main]
 6  pull_request:
 7    branches: [main]
 8
 9jobs:
10  build:
11    runs-on: ubuntu-latest
12    steps:
13      - uses: actions/checkout@v4
14
15      - name: Set up Python 3.12
16        uses: actions/setup-python@v5
17        with:
18          python-version: "3.12"
19
20      - name: Install dependencies
21        run: pip install -r requirements.txt
22
23      - name: Build HTML (warnings = errors)
24        run: sphinx-build -W -b html source/ build/html
25
26      - name: Check for broken links
27        run: sphinx-build -b linkcheck source/ build/linkcheck
28
29      - name: Deploy to GitHub Pages
30        if: github.ref == 'refs/heads/main'
31        uses: peaceiris/actions-gh-pages@v4
32        with:
33          github_token: ${{ secrets.GITHUB_TOKEN }}
34          publish_dir: ./build/html

Writing a Custom Sphinx Extension

Custom Python extensions unlock unlimited possibilities — from version badges to glossary auto-generators. Every extension follows the same setup(app) contract:

_extensions/version_badge.py — Custom Sphinx directive
from docutils import nodes
from docutils.parsers.rst import Directive, directives


class VersionBadge(Directive):
    """Renders a coloured version badge inline in HTML output."""

    required_arguments = 1
    option_spec = {"color": directives.unchanged}

    def run(self):
        version = self.arguments[0]
        color   = self.options.get("color", "#0f3460")
        html    = (
            f'<span class="badge" style="background:{color};'
            f'color:#fff;padding:.2rem .7rem;border-radius:12px;">'
            f'v{version}</span>'
        )
        return [nodes.raw("", html, format="html")]


def setup(app):
    app.add_directive("version-badge", VersionBadge)
    return {"version": "0.1", "parallel_read_safe": True}
Using the custom directive anywhere in the project
.. version-badge:: 2.4.1
   :color: #4ecca3