Skip to contentSkip to Content
Migrating from Sphinx

Migrating from Sphinx

Step-by-step guide to moving your project from Sphinx to folio.

Why migrate

Simpler configuration. Sphinx uses a Python conf.py file that can grow to hundreds of lines with complex extension configurations. folio uses a single docs.yaml file that is typically under 30 lines.

Modern UI. folio generates a responsive, dark-mode-enabled site with a component-based UI built on Next.js and shadcn/ui. No theme hunting or template customization required.

Faster iteration. The dev server supports hot reload — edit your docstrings and see changes instantly without running a full rebuild.

Zero-config API docs. Point folio at your source directories and it automatically generates API reference pages. No autodoc directives, no .. automodule:: boilerplate.

Step-by-step migration

1. Install folio

uv add folio-docs

2. Initialize configuration

Run the init command in your project root. It detects your project name, version, and source layout from pyproject.toml:

uv run folio init

This creates a docs.yaml file. Edit it to point to your Python source directories:

project: name: "my-project" version: "1.0.0" repo: "https://github.com/org/my-project" source: python: paths: - "src/my_project/" exclude: - "src/my_project/_vendor/" docs: - "docs/" nav: - "Guide" - "API Reference"

3. Convert existing documentation

If you have hand-written documentation in .rst format, convert it to Markdown before adding it to source.docs. Folio includes an RST-to-MDX converter for common directives, but the documentation source pipeline currently treats Markdown files as the supported page format.

4. Update Sphinx-style docstrings

Folio supports Google-style and NumPy-style docstrings natively — if your project uses NumPy-style docstrings, just set source.python.docstring_style: "numpy" (or rely on "auto") and no conversion is needed. Only Sphinx-style docstrings (:param name:) need to be converted. Here is a comparison:

Sphinx style
def connect(host, port=8080):
  """Connect to a server.

  :param host: The hostname.
  :type host: str
  :param port: The port number.
  :type port: int
  :returns: A connection object.
  :rtype: Connection
  :raises ConnectionError: If unreachable.
  """
Google style
def connect(host: str, port: int = 8080) -> Connection:
  """Connect to a server.

  Args:
      host: The hostname.
      port: The port number.

  Returns:
      A connection object.

  Raises:
      ConnectionError: If unreachable.
  """

5. Remove Sphinx configuration

Once migration is complete, you can remove Sphinx-related files:

  • conf.py
  • Makefile (if only used for docs)
  • make.bat
  • _build/ directory
  • _static/, _templates/ directories
  • Sphinx from your dependencies

6. Build and verify

folio serve

This starts a dev server at http://localhost:4321 where you can verify your documentation looks correct.

Mapping Sphinx concepts to folio

conf.py to docs.yaml

Sphinx conf.pyfolio docs.yaml
project = "Name"project.name: "Name"
version = "1.0"project.version: "1.0"
extensions = ["autodoc"]Not needed (automatic)
html_theme = "furo"Built-in theme (see Theming guide)
html_static_pathCustom assets copied by a plugin or referenced from docs
html_logotheme.logo
html_favicontheme.favicon
exclude_patternssource.python.exclude
autodoc_member_orderNot configurable (source order)

autodoc to automatic generation

In Sphinx, you write explicit directives to pull in API documentation:

.. automodule:: my_project.core :members: :undoc-members: :show-inheritance:

In folio, you simply list your source directories and everything is documented automatically:

source: python: paths: - "src/my_project/"

No per-module directives needed. Use __all__ in your Python modules to control which symbols appear in the documentation.

RST directives

Folio’s RST converter handles common directives during migration. Use the converted Markdown/MDX output as your source documentation. Here is what the converter supports:

Supported directives:

RST DirectiveConverted To
.. code-block:: pythonFenced code block (```python)
.. note::Callout (info)
.. warning::Callout (warning)
.. tip::Callout (tip)
.. hint::Callout (tip)
.. danger::Callout (danger)
.. error::Callout (danger)
.. important::Callout (warning)
.. caution::Callout (warning)
.. attention::Callout (warning)
.. seealso::Callout (info)
.. deprecated::Callout (danger) with version
.. versionadded::Callout (note) with version
.. versionchanged::Callout (note) with version
.. image:: path![path](path)
RST headings (underlines)Markdown headings (#, ##, etc.)
inline code `inline code`
:role:`text``text`

Not supported:

RST FeatureStatus
.. toctree::Not needed (auto-generated navigation)
.. include::Not supported
.. math::Not supported
.. table::Use Markdown tables instead
.. raw::Not supported
.. only::Not supported
Cross-references (:ref:, :doc:)Not yet supported
Substitutions (|name|)Not supported
Field lists (:field:)Not supported
FootnotesNot supported

Sphinx extensions to Folio features

Many common Sphinx extension use cases are built into Folio. Custom extension authoring is not part of the public MVP surface yet.

Sphinx Extensionfolio Equivalent
autodocBuilt-in (automatic)
napoleonBuilt-in (Google style)
viewcodeSource file + line tracking (built-in)
intersphinxNot yet supported
todoNot yet supported
coverageNot yet supported
doctestNot yet supported
sphinx-copybuttonBuilt-in (code blocks have copy buttons)
Custom extensionsNot public in the MVP

make html to folio build

Sphinx Commandfolio Command
make htmlfolio build
make cleanfolio clean
sphinx-autobuildfolio serve
sphinx-quickstartfolio init

What works differently

Sphinx-style docstrings require conversion

folio supports both Google-style and NumPy-style docstrings. If your project uses NumPy-style docstrings, set source.python.docstring_style: "numpy" in your docs.yaml and no conversion is needed. If your project uses Sphinx (:param:) style, you need to convert them to either Google or NumPy style. This is the most significant migration effort for projects using Sphinx-style docstrings.

Tools like pyment can help automate docstring conversion:

uv tool run pyment -w -o google src/

Sphinx role cross-references require conversion

Sphinx has a powerful cross-reference system (:class:, :func:, :meth:, etc.) that creates links between documented symbols. folio generates API links for parsed type annotations, but it does not support Sphinx role syntax yet. Role syntax like :class:\MyClass`is converted to inline code (``MyClass` “) and should be replaced with Markdown links where needed.

No intersphinx

Sphinx’s intersphinx extension lets you link to other projects’ documentation. folio does not yet support this. If your docs heavily link to external API documentation (e.g., linking to Python stdlib docs), those links will need to be replaced with plain URLs or removed.

Source order, not alphabetical

folio documents members in the order they appear in the source file. Sphinx’s autodoc_member_order option with alphabetical sorting has no equivalent.

No RST-only features in docstrings

If your docstrings use RST features like field lists, substitutions, or complex table markup, they will not be converted. Stick to plain text and Google-style sections in docstrings.

Common gotchas

Docstring parsing errors. If a docstring does not follow Google style correctly, the parser falls back to treating the entire text as a plain description. Indentation matters — section content must be indented under the section header.

Missing __init__ docs. folio documents __init__ like any other method. If you were relying on Sphinx’s autoclass_content = "both" to merge class and __init__ docstrings, you may need to adjust your docstrings.

Private members. By default, folio documents all top-level definitions. Use __all__ to control what gets included, or rely on the convention that names starting with _ are excluded from __all__.

RST in Markdown files. If your Markdown files contain RST directives wrapped in \{eval-rst\} blocks, these are stripped during conversion. Replace them with Markdown equivalents.

Curly braces in Markdown. Since folio outputs MDX (Markdown + JSX), bare curly braces \{ and \} in your Markdown files are interpreted as JSX expressions. If your docs contain literal curly braces (e.g., in code explanations outside of code blocks), they will need to be escaped or placed in code blocks.

Feature comparison

FeatureSphinxfolio
Python API docsVia autodoc extensionBuilt-in, automatic
Docstring stylesGoogle, NumPy, SphinxGoogle, NumPy
ConfigurationPython (conf.py)YAML (docs.yaml)
Output formatHTML, PDF, ePub, etc.HTML (Next.js)
Theme systemJinja2 templatesReact + shadcn/ui
Dark modeTheme-dependentBuilt-in
Hot reload dev serverVia sphinx-autobuildBuilt-in
SearchBuilt-inBuilt-in (Pagefind)
Cross-referencesFull supportGenerated API type links; Sphinx roles not yet
IntersphinxFull supportNot yet
RST supportNativePartial migration converter
Markdown supportVia MySTNative
Custom extensionsExtensive plugin ecosystemNot public in the MVP
PDF outputBuilt-inNot supported
i18nBuilt-inNot yet
LLM-friendly outputNot built-inllms.txt + llms-full.txt
Custom componentsJinja2 macrosReact/MDX components
Setup complexityHighLow
Build speedModerateFast (Turbopack)

Migration checklist

  • OK

    Install Folio and run folio init

  • OK

    Edit docs.yaml with project details and source paths

  • WARN

    Convert Sphinx-style docstrings

    Use Google or NumPy style. NumPy-style docstrings are supported with source.python.docstring_style: "numpy".

  • WARN

    Convert .rst files to .md

    Use the migration converter for common directives or your preferred tooling.

  • TODO

    Replace :ref: and :doc: cross-references

    Use Markdown links or inline code where links are not available yet.

  • TODO

    Remove {eval-rst} blocks from Markdown

  • TODO

    Move custom static assets into documented source assets or plugin output

  • TODO

    Run folio serve and verify every page

  • TODO

    Remove Sphinx configuration files and dependencies

  • TODO

    Update CI/CD scripts to use folio build