mkdocstrings: injecting API documentation into MkDocs pages from source code
:blue_book: Automatic documentation from sources, for MkDocs.
At a glance
- What is it?
- mkdocstrings is a MkDocs plugin that pulls API documentation out of source code and places it inside Markdown files through a `::: identifier` directive. The base package ships with no language support; every target language requires a separate handler, and the Python handler is the most complete one available.
- Who is it for?
- mkdocstrings is worth adopting when your project uses MkDocs and you want API reference pages generated from docstrings without writing them by hand. Python is the most mature handler, and pairing it with Material for MkDocs produces clean output.
- Can I use it commercially?
- Yes. ISC is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 8 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 6, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The ::: identifier directive and the 4-spaces YAML block that follows it
The injection syntax is a single line beginning with three colons and a dotted identifier. Place `::: my_library.my_module.my_class` in any Markdown page, and mkdocstrings intercepts it during the MkDocs build, passes the identifier to the appropriate handler, and inserts the rendered documentation in place of that line.
An optional YAML block placed after the directive, indented exactly four spaces, carries per-injection overrides. Those overrides go to the handler that processes the identifier, so the available keys depend entirely on which handler is active, not on mkdocstrings itself. A class and a module can sit on the same page with different YAML blocks controlling how each one renders.
One Markdown file can hold several `::: ` directives pointing at different identifiers. A hand-written narrative can share a page with generated API entries without a separate build step. The project documentation calls this inline injection, distinguishing it from tools that generate separate Markdown files for each documented object and require you to add those files to the navigation manually.
Handler architecture: the base package contributes no language parser
The `mkdocstrings` package provides the injection parser, the Jinja2 template engine, cross-reference infrastructure, and the theming layer, but it contains no code that reads source files. Language support lives entirely in separate handler packages. Handlers are published for C, Crystal, GitHub Actions, Python, MATLAB, TypeScript, VBA, and shell scripts. A `BaseHandler` API is exposed for any language not yet covered.
This split has a direct consequence during setup: installing `mkdocstrings` alone produces a plugin that will either error or silently skip every `::: ` directive, depending on how the handler is configured. This separation is explicit in pyproject.toml. Under `[project.optional-dependencies]`, handlers appear separately: `python` maps to `mkdocstrings-python>=1.16.2` and `crystal` maps to `mkdocstrings-crystal>=0.3.4`. Neither is listed as a core dependency.
Theme support also lives at the handler level. Currently, the Python handler offers Material theme support alongside basic support for the ReadTheDocs and MkDocs themes. Other handlers may offer different sets, and the project documentation covers theming in a dedicated section.
Installing mkdocstrings with Python support via pip or conda
Two pip paths lead to the same result for Python projects. One form uses the extras syntax to install the base package and the Python handler together:
pip install 'mkdocstrings[python]'Alternatively, installing the handler package directly also pulls in `mkdocstrings` as a dependency:
pip install mkdocstrings-pythonUsing the direct handler form gives more control over the accepted version range; the extras form sets `mkdocstrings-python>=1.16.2` as the lower bound and any project using the extras form inherits that constraint automatically.
For conda environments:
conda install -c conda-forge mkdocstrings mkdocstrings-pythonAmong the core dependencies listed in pyproject.toml, `mkdocs>=1.6`, `Jinja2>=3.1`, and `pymdown-extensions>=6.3` are required directly; the cross-reference mechanism relies on `mkdocs-autorefs>=1.4`. The build backend is pdm-backend, and `requires-python` is set to `>=3.10`.
Adding mkdocstrings to mkdocs.yml and writing a first reference page
A minimal working configuration requires two entries in mkdocs.yml: a theme and the plugin name. A quick usage example from the README uses Material theme:
site_name: "My Library"
theme:
name: "material"
plugins:
- search
- mkdocstringsWith that file saved, any Markdown page can inject a documented object:
# Reference
::: my_library.my_module.my_classWith that page included in the navigation, MkDocs renders the class documentation in place of the directive. Global handler options go under the `mkdocstrings` plugin entry in mkdocs.yml, while per-injection options go in the 4-spaces YAML block that follows the directive in the Markdown file. Each per-injection block overrides the global defaults only for that one object.
Cross-references within a site, and the opt-in change since version 0.15
mkdocstrings adds a link syntax on top of standard Markdown. Writing `[identifier][]` or `[title][identifier]` in any page resolves to wherever that identifier was rendered, without the author needing to know which page holds it. This works for any heading that a language handler generates.
A behavioral change at version 0.15 is worth noting for anyone upgrading an existing installation. Before version 0.15, all Markdown headings on all pages were automatically included in the global referencing scheme. Since version 0.15, that automatic inclusion no longer applies, and you must explicitly opt headings into the scheme. A site that relied on automatically resolved headings for navigation links will silently lose those links when upgraded past 0.15 unless the opt-in is applied. The README flags this change directly in the cross-references feature description.
For new projects starting above version 0.15, the opt-in model is the only one that exists. Handler-generated headings are already part of the scheme by default; the opt-in is only required for Markdown headings you write by hand.
Cross-site references require the other project to publish an inventory
Cross-site references follow the same model as Sphinx's intersphinx extension. When another library exposes an inventory file and you load that inventory in your mkdocs.yml configuration, `[identifier][]` links can resolve into that library's documentation site without you hard-coding the URL.
The feature works only as well as the inventories that other projects choose to publish. Loading another project's inventory in mkdocs.yml is your configuration step; whether the other project publishes a compatible inventory at all is outside your control. Both conditions must be met: the other project must publish an inventory, and you must load it in your mkdocs.yml configuration.
The Development Status Beta classifier in pyproject.toml contradicts the 1.0.x version number
A detail in pyproject.toml that a quick scan could miss: the classifiers list includes `Development Status :: 4 - Beta`. That label appears in PyPI search results and is the stage descriptor that package tooling reads. Version 1.0.6 came out on 2026-07-11, the repository was last pushed on 2026-10-03, and the ISC license governs the code.
A 1.0.x version number conventionally signals a stable public API, but the Beta classifier sends the opposite message. Whether this reflects a considered position on interface stability or a maintenance oversight, readers who treat version numbers as stability signals should verify the project history before pinning mkdocstrings in a production dependency set.
Where Sphinx autodoc fits better than mkdocstrings
mkdocstrings is built around MkDocs. If a project uses Sphinx, Docusaurus, Hugo, or any other static site generator, this plugin does not apply. Sphinx's autodoc extension handles docstring injection within Sphinx documentation directly, without any involvement from mkdocstrings.
For a project that already has working Sphinx documentation with cross-site references from other libraries, moving to MkDocs breaks all incoming inventory links unless those libraries also publish MkDocs-compatible inventories. Cross-site references in mkdocstrings depend on the other project publishing an inventory you can load in your mkdocs.yml, which is a condition outside your control.
Currently, the Python handler's theme support covers Material, ReadTheDocs, and MkDocs themes. Material for MkDocs is a separate package maintained outside this project; the visual quality of the output depends on having it installed and configured. ReadTheDocs and MkDocs themes carry only basic handler support, according to the README.
Editorial conclusion
mkdocstrings is worth adopting when your project uses MkDocs and you want API reference pages generated from docstrings without writing them by hand. Python is the most mature handler, and pairing it with Material for MkDocs produces clean output. The base package does nothing without a handler, so verify your language has one before you start. For Python, the pinned constraint in pyproject.toml is mkdocstrings-python>=1.16.2, and that lower bound propagates into your dependency set. Teams already on Sphinx should weigh the cost of broken cross-site inventory links before switching.
Frequently asked questions
Does mkdocstrings work with languages other than Python?
The project is language-agnostic and uses a handler model. The README lists handlers for C, Crystal, GitHub Actions, Python, MATLAB, TypeScript, VBA, and shell scripts. The base package handles no language-specific parsing on its own.
How do I add mkdocstrings to an existing MkDocs site?
Add `mkdocstrings` to the plugins list in mkdocs.yml and install the package with a language handler. For Python, the README gives `pip install 'mkdocstrings[python]'` as the install command.
What changed about cross-references in mkdocstrings version 0.15?
Before version 0.15, all Markdown headings were automatically included in the global cross-reference scheme. From version 0.15 onward, you must opt headings in explicitly; the automatic behavior no longer applies.
What is the difference between installing mkdocstrings[python] and mkdocstrings-python?
Both install the Python handler and mkdocstrings together. Installing mkdocstrings-python directly gives more control over the accepted handler version range, as the README notes.
What Python version does mkdocstrings require?
The pyproject.toml sets requires-python to 3.10 or newer and includes classifiers for Python 3.10 through 3.15. Older Python versions are not supported.