Library / SDK
executablebooks/markdown-it-py avatar
executablebooks/markdown-it-py

markdown-it-py: Configurable CommonMark Parsing in Python

Markdown parser, done right. 100% CommonMark support, extensions, syntax plugins & high speed. Now in Python!

1,382 stars139 forksPythonMIT

At a glance

What is it?
markdown-it-py is a Python parser based on the CommonMark specification, with a configurable rule system, plugins, token parsing, and HTML rendering. It suits applications that need explicit control over accepted Markdown syntax rather than a fixed parser configuration.
Who is it for?
Adopt markdown-it-py when a Python application needs configurable CommonMark parsing, accessible token output, or optional syntax plugins. Do not choose it solely from the project's speed claims if a Rust binding is a better operational fit.
Can I use it commercially?
Yes. MIT 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 5 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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why markdown-it-py Exposes CommonMark as a Python Parser

markdown-it-py addresses applications that must convert Markdown but also need deliberate control over syntax. Its baseline follows the CommonMark specification, while its configuration can add rules or replace existing ones. That makes the library relevant to documentation systems, static-site tooling, content pipelines, editors, and Python services that process user-supplied Markdown.

The project is a Python port of `markdown-it` and some associated plugins. That origin matters because the Python package preserves the idea of a configurable parser rather than exposing only a single `markdown_to_html()` function. Developers can select a preset, pass options such as `breaks` and `html`, enable rules such as `table`, and attach plugins.

The README describes tables as disabled by default to match CommonMark. Applications expecting GitHub-style tables must account for that distinction instead of assuming that every Markdown extension is active. The same is true for HTML: the example explicitly enables it with `"html": True`, so safe handling of embedded HTML remains an application-level decision.

markdown-it-py Parses Tokens Before Rendering HTML

The documented Python workflow separates parsing from rendering. A `MarkdownIt` instance first receives Markdown through `md.parse(text)`. The result is assigned to `tokens`, giving the application an intermediate representation. The same configured instance can then call `md.render(text)` to produce `html_text`.

That two-stage API supports inspection and transformation between parsing and output. The README does not present token modification in its example, so it would be inaccurate to claim a specific mutation recipe. It does establish that parsing returns tokens while rendering produces HTML. The configuration is attached to the parser instance, including its preset, options, enabled rules, and installed plugins.

The example composes these mechanisms through `MarkdownIt("commonmark", {"breaks": True, "html": True})`. It then applies `front_matter_plugin` and `footnote_plugin` through `.use(...)` before enabling `"table"`. Plugin functions receive the configured parser as part of this composition, allowing extensions to participate without replacing the core call structure.

This architecture is the main difference from treating Markdown conversion as an opaque text substitution. A tool that only needs a rendered string can stop at `render`, while an application needing token access can use the parser output. Applications that modify tokens must check the plugin and renderer contracts in the project documentation because the README does not explain those contracts.

Installing markdown-it-py with Plugins, Linkification, or Conda

The primary pip installation documented by the README includes the package's plugin extra:

bash
pip install markdown-it-py[plugins]

This form installs `markdown-it-py` together with the `plugins` extra, which `pyproject.toml` defines as `mdit-py-plugins>=0.5.0`. It is the documented starting point for the front matter and footnote examples.

Link support has a separate extra. Projects that need both linkification and plugins can install:

bash
pip install markdown-it-py[linkify,plugins]

The `linkify` extra depends on `linkify-it-py>=1,<3`. The package metadata requires Python `>=3.10`, so an older runtime must be addressed before installation. The available classifiers also list CPython and PyPy implementations, but the README does not provide a separate PyPy installation procedure.

Conda users have an alternative channel-based installation:

bash
conda install -c conda-forge markdown-it-py

The documented Conda command for the extras installs the package, `linkify-it-py`, and `mdit-py-plugins` together. That command differs from the pip command in naming the optional packages directly rather than using extras.

A First CommonMark, Plugin, and Table Parse

The following example comes from the README. It enables line-break behavior and HTML, installs front matter and footnote plugins, enables tables, parses the input into `tokens`, and renders the same input as `html_text`.

python
from markdown_it import MarkdownIt
from mdit_py_plugins.front_matter import front_matter_plugin
from mdit_py_plugins.footnote import footnote_plugin

md = (
    MarkdownIt("commonmark", {"breaks": True, "html": True})
    .use(front_matter_plugin)
    .use(footnote_plugin)
    .enable("table")
)
text = """
---
a: 1
---

a | b
- | -
1 | 2

A footnote [^1]

[^1]: some details
"""
tokens = md.parse(text)
html_text = md.render(text)

At this point, `tokens` contains the parser output and `html_text` contains the rendered document. The README also includes commented lines for writing `html_text` to `output.html`, but leaves them commented because immediate file export is optional.

For a command-line conversion, the installed package exposes `markdown-it`. This command converts two files and redirects the output into `index.html`:

bash
markdown-it README.md README.footer.md > index.html

Tables remain disabled unless `--enable-tables` is present:

bash
markdown-it --enable-tables README.md > index.html

For standard input, the documented form is:

bash
markdown-it --enable-tables --stdin < README.md > index.html

Without filenames, the command enters interactive mode. Its help text instructs the user to press `Ctrl-D` to complete input or `Ctrl-C` to exit.

Rule Configuration and Plugins Define the Accepted Syntax

The useful extension point is the `MarkdownIt` instance. It can be created from the `"commonmark"` preset, receive parser options, have plugin functions applied with `.use(...)`, and enable named rules with `.enable(...)`. The README says users can add new rules and even replace existing ones, but it does not document every public rule-management method beyond the methods used in its examples.

Plugins are not limited to the two shown here. The package metadata defines the `plugins` extra as `mdit-py-plugins>=0.5.0`, and the README links to a separate plugin list. Developers should select extensions against that documented plugin interface rather than assuming that every Markdown extension has an equivalent implementation.

The configuration also controls a meaningful trust boundary. In the example, `"html": True` enables HTML handling. The README calls configuration "easy" for security but does not publish a specific sanitization policy in its README excerpt. Enabling HTML is therefore a deliberate choice, not something to copy without checking whether untrusted authors may submit raw HTML. The project's separate security page is the appropriate source for that policy.

Rule replacement offers more control than simply switching a feature on. It also raises the upgrade cost because custom behavior must remain compatible with the parser's rendering and token interfaces. The repository includes `tests/`, `tox.ini`, and `CHANGELOG.md`, but the README does not quantify migration effort for custom plugins.

Limits of the Python Port and the Rust-Binding Alternative

The most visible limitation is language and runtime scope. This package is a Python port, and its metadata requires Python `>=3.10`. Its optional extras add dependencies, which increases setup work when plugins or linkification are needed. A deployment that does not allow additional Python packages may have to omit those features or choose another packaging route.

The README does not claim that every `markdown-it` plugin has a Python equivalent. It says that this project is a port of `markdown-it` and some associated plugins, then directs users to a plugin list. Compatibility gaps therefore need to be checked for the exact syntax an application expects.

`markdown-it-pyrs` is a concrete alternative with a different implementation approach. The README describes it as an experimental Rust binding and says it offers "even more speed." It targets the parser ecosystem through a binding rather than the pure Python port represented by this repository. The project metadata also includes `markdown-it-pyrs` in the `compare` extra, which confirms it as a comparison target.

That claim does not establish that the Rust binding should replace `markdown-it-py`. The README labels it experimental and does not document a drop-in installation, API parity, or operational trade-offs. Teams choosing between them would need to verify interface compatibility and deployment requirements rather than selecting solely from the speed statement.

Release Activity, Python Support, and MIT Upgrade Considerations

The repository is not archived, and the last push was on 2026-10-12. Recent releases include v4.2.0 on 2026-05-07, v4.1.0 on 2026-05-06, and v4.0.0 on 2025-08-11. The package metadata classifies the project as `Development Status :: 5 - Production/Stable`, although classification is a packaging declaration rather than a guarantee for every plugin combination.

Maintenance signals are recent, but upgrades still involve dependency and behavior checks. The core dependency is `mdurl~=0.1`. The plugin extra requires `mdit-py-plugins>=0.5.0`, while linkification requires `linkify-it-py>=1,<3`. Applications using these extras should account for both `markdown-it-py` and `mdit-py-plugins` when reviewing an upgrade.

The repository is distributed under the MIT License. The repository also contains `LICENSE.markdown-it`, reflecting the ported project's licensing materials. Projects should review both files for their own attribution and notice obligations, but this is a compliance check rather than legal advice.

The README links `CHANGELOG.md`, the documentation, and a security page, yet it does not document a rollback procedure. An upgrade should therefore be evaluated against the project's changelog and tests before replacing a working parser in a content pipeline.

Editorial conclusion

Adopt markdown-it-py when a Python application needs configurable CommonMark parsing, accessible token output, or optional syntax plugins. Do not choose it solely from the project's speed claims if a Rust binding is a better operational fit. Check plugin compatibility, HTML handling policy, required Python version, and expected output before integration. For the documented baseline, Python 3.10 or later and `markdown-it-py[plugins]` are the first boundaries to verify.

Frequently asked questions

How do I install markdown-it-py with plugins?

Install `markdown-it-py[plugins]`. The `plugins` extra depends on `mdit-py-plugins>=0.5.0` according to `pyproject.toml`.

How do I convert a Markdown file to HTML with markdown-it-py?

Pass one or more filenames to the `markdown-it` command and redirect standard output. Add `--enable-tables` if the source contains tables, because tables are disabled by default.

What is the difference between md.parse() and md.render() in markdown-it-py?

`md.parse(text)` returns parser tokens, while `md.render(text)` returns rendered HTML. The README demonstrates both calls using the same configured `MarkdownIt` instance.

Official sources

  1. executablebooks/markdown-it-py on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/executablebooks-markdown-it-py.svg)](https://hysenlabs.com/projects/executablebooks-markdown-it-py)

Was this useful?