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-docs2. 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 initThis 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:
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.
"""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.pyMakefile(if only used for docs)make.bat_build/directory_static/,_templates/directories- Sphinx from your dependencies
6. Build and verify
folio serveThis 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.py | folio 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_path | Custom assets copied by a plugin or referenced from docs |
html_logo | theme.logo |
html_favicon | theme.favicon |
exclude_patterns | source.python.exclude |
autodoc_member_order | Not 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 Directive | Converted To |
|---|---|
.. code-block:: python | Fenced 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 |  |
| RST headings (underlines) | Markdown headings (#, ##, etc.) |
inline code | `inline code` |
:role:`text` | `text` |
Not supported:
| RST Feature | Status |
|---|---|
.. 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 |
| Footnotes | Not 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 Extension | folio Equivalent |
|---|---|
autodoc | Built-in (automatic) |
napoleon | Built-in (Google style) |
viewcode | Source file + line tracking (built-in) |
intersphinx | Not yet supported |
todo | Not yet supported |
coverage | Not yet supported |
doctest | Not yet supported |
sphinx-copybutton | Built-in (code blocks have copy buttons) |
| Custom extensions | Not public in the MVP |
make html to folio build
| Sphinx Command | folio Command |
|---|---|
make html | folio build |
make clean | folio clean |
sphinx-autobuild | folio serve |
sphinx-quickstart | folio 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
| Feature | Sphinx | folio |
|---|---|---|
| Python API docs | Via autodoc extension | Built-in, automatic |
| Docstring styles | Google, NumPy, Sphinx | Google, NumPy |
| Configuration | Python (conf.py) | YAML (docs.yaml) |
| Output format | HTML, PDF, ePub, etc. | HTML (Next.js) |
| Theme system | Jinja2 templates | React + shadcn/ui |
| Dark mode | Theme-dependent | Built-in |
| Hot reload dev server | Via sphinx-autobuild | Built-in |
| Search | Built-in | Built-in (Pagefind) |
| Cross-references | Full support | Generated API type links; Sphinx roles not yet |
| Intersphinx | Full support | Not yet |
| RST support | Native | Partial migration converter |
| Markdown support | Via MyST | Native |
| Custom extensions | Extensive plugin ecosystem | Not public in the MVP |
| PDF output | Built-in | Not supported |
| i18n | Built-in | Not yet |
| LLM-friendly output | Not built-in | llms.txt + llms-full.txt |
| Custom components | Jinja2 macros | React/MDX components |
| Setup complexity | High | Low |
| Build speed | Moderate | Fast (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