The multimark package has Python bindings to cmark-gfm, the C reference implementation of CommonMark with GitHub Flavored Markdown extensions.
Renders Markdown to HTML, LaTeX, groff man, XML, and normalized CommonMark: all from a single, lightweight package.
pip install multimarkWheels are available for Linux, macOS, and Windows (Python 3.9+). No system dependencies required.
from multimark import markdown_to_html, markdown_to_latex
html = markdown_to_html("**Hello**, *world*!")
# '<p><strong>Hello</strong>, <em>world</em>!</p>\n'
latex = markdown_to_latex("**Hello**, *world*!")
# '\\textbf{Hello}, \\emph{world}!\n'| Function | Output Format |
|---|---|
markdown_to_html() |
HTML |
markdown_to_latex() |
LaTeX |
markdown_to_man() |
groff man page |
markdown_to_commonmark() |
Normalized CommonMark |
markdown_to_xml() |
XML (AST representation) |
Use named boolean keyword arguments for common settings:
from multimark import markdown_to_html, markdown_to_latex
# Smart punctuation (curly quotes, em-dashes)
markdown_to_html('"Hello" -- world...', smart=True)
# '<p>\u201cHello\u201d \u2013 world\u2026</p>\n'
# Allow raw HTML passthrough (safe mode is the default)
markdown_to_html('<div>hi</div>', unsafe=True)
# '<div>hi</div>\n'
# Source position attributes
markdown_to_html('**Hello**', sourcepos=True)
# '<p data-sourcepos="1:1-1:9"><strong>Hello</strong></p>\n'
# Line wrapping (LaTeX, man, and commonmark renderers)
markdown_to_latex('**Hello**, *world*!', width=80)
# '\\textbf{Hello}, \\emph{world}!\n'
# Footnotes
markdown_to_html('Text[^1]\n\n[^1]: A footnote\n', footnotes=True)
# '<p>Text<sup class="footnote-ref">...</sup></p>\n<section class="footnotes">...\n'Or compose flags with the Options bitmask:
from multimark import markdown_to_html, Options
html = markdown_to_html(text, options=Options.SMART | Options.UNSAFE)Enable GitHub Flavored Markdown extensions by name:
from multimark import markdown_to_html
# Tables
markdown_to_html('| A | B |\n|---|---|\n| 1 | 2 |\n', extensions=["table"])
# '<table>\n<thead>\n<tr>\n<th>A</th>\n<th>B</th>\n</tr>...\n'
# Strikethrough
markdown_to_html('~~deleted~~', extensions=["strikethrough"])
# '<p><del>deleted</del></p>\n'
# Multiple extensions
html = markdown_to_html(text, extensions=["table", "strikethrough", "autolink", "tasklist", "tagfilter"])Available extensions: table, strikethrough, autolink, tagfilter, tasklist.
Every renderer accepts:
text: Markdown stringoptions: raw bitmask (default0)extensions: list of GFM extension names (default())smart: smart punctuationhardbreaks: render soft breaks as<br>unsafe: allow raw HTMLnormalize: consolidate adjacent text nodesfootnotes: enable footnote syntax
Additional parameters:
sourcepos: Source position attributes (HTML and XML only)width: Line wrap column (LaTeX, man, and commonmark only;0= no wrap)
Several Python packages wrap cmark or provide CommonMark parsing. Here's how they compare:
| multimark | cmarkgfm | commonmark.py | |
|---|---|---|---|
| Engine | cmark-gfm (C, vendored) | cmark-gfm (C, vendored) | Pure Python |
| Output formats | HTML, LaTeX, man, XML, CommonMark | HTML only | HTML only |
| GFM extensions | ✓ | ✓ | ✗ |
| Safe by default | ✓ | ✓ | ✗ |
| Convenience kwargs | smart=True, unsafe=True, etc. |
Raw bitmask only | N/A |
| Performance | Fastest (14% faster than cmarkgfm) | Fast | ~31× slower |
| Maintained | Active (2026) | Active (2025) | Unmaintained (2019) |
multimark uses the same battle-tested C library as cmarkgfm but exposes all five of cmark's output formats (not just HTML). The API is designed around keyword arguments rather than opaque bitmasks, and unsafe content is blocked by default so the safe choice requires no extra configuration.
Thanks to extension pointer caching and reduced Python-side overhead, multimark is the fastest Python Markdown-to-HTML library. Take a look at the benchmarks for more detail on this.
MIT and BSD-2-Clause (cmark-gfm).
