mdka
A HTML to Markdown converter written in Rust.
mdka balances conversion quality with runtime efficiency —
correct, readable Markdown from real-world HTML, at competitive speed and
near-flat memory.
"ka" means "化 (か)" pointing to conversion.
Why mdka?
There are several good HTML-to-Markdown converters in the Rust ecosystem. mdka's specific focus is:
- Reliable output from diverse HTML sources. It is built on scraper, which uses html5ever — the HTML5 parser from the Servo browser engine. html5ever applies the same parsing algorithm that web browsers use, so it handles malformed tags, deeply nested structures, CMS output, and SPA-rendered DOM without special-casing.
- Crash resistance. Conversion uses non-recursive DFS throughout. There is no stack overflow, no matter the nesting depth. That is a claim about crashing, not speed — deep nesting still costs real time, quadratically; see Scaling: Depth and Width.
- Configurable pre-processing.
Five conversion modes, of which two convert
differently:
Balanced(the default) andMinimal, which strips to body text and structure for LLM input. The other three are aliases ofBalanced— see Conversion Modes. - Multi-language. The same Rust implementation is accessible from Node.js (napi-rs) and Python (PyO3).
Quick Start
Try it from the command line
Download a prebuilt binary (no Rust toolchain needed) from the latest release:
| Platform | Asset |
|---|---|
| Linux x64 (glibc 2.17 or newer) | mdka@Linux-x64-gnu-<version>.tar.gz |
| Linux x64 (musl, static) | mdka@Linux-x64-musl-<version>.tar.gz |
| Linux aarch64 (musl, static) | mdka@Linux-aarch64-musl-<version>.tar.gz |
| macOS Apple Silicon | mdka@macOS-aarch64-<version>.zip |
| Windows x64 | mdka@Windows-x64-<version>.zip |
The glibc archive is built against glibc 2.17, so it runs on Ubuntu 20.04, Debian 11 and RHEL 8 as well as newer systems; the musl archives have no glibc requirement at all.
Other platforms (macOS Intel, Windows ARM, Linux aarch64 glibc) aren't built
as binaries — use cargo install mdka-cli below instead.
Extract the archive; it contains one folder holding the mdka binary. Replace
<version> with the release you downloaded (for example 2.6.0).
Linux — use your archive's name (Linux-x64-gnu, Linux-x64-musl or
Linux-aarch64-musl) in the first two lines:
tar xzf mdka@Linux-x64-gnu-<version>.tar.gz
cd mdka@Linux-x64-gnu-<version>
echo '<h1>Hello</h1><p><strong>world</strong></p>' | ./mdka
# # Hello
#
# **world**
macOS:
unzip mdka@macOS-aarch64-<version>.zip
cd mdka@macOS-aarch64-<version>
echo '<h1>Hello</h1><p><strong>world</strong></p>' | ./mdka
# # Hello
#
# **world**
Windows (PowerShell):
Expand-Archive mdka@Windows-x64-<version>.zip -DestinationPath .
cd mdka@Windows-x64-<version>
'<h1>Hello</h1><p><strong>world</strong></p>' | .\mdka.exe
# # Hello
#
# **world**
Or install via cargo — requires cargo (Rust language) installed:
cargo install mdka-cli
echo '<h1>Hello</h1><p><strong>world</strong></p>' | mdka
# # Hello
#
# **world**
mdka page.html # → page.md (same directory)
mdka --mode minimal --drop-shell -o out/ *.html # strip nav/header/footer
mdka --help # full option list
Add to a Rust project
# Cargo.toml
[dependencies]
mdka = "2"
use mdka::html_to_markdown;
let md = html_to_markdown("<h1>Hello</h1><p><em>world</em></p>");
// "# Hello\n\n*world*\n"
With options:
use mdka::html_to_markdown_with;
use mdka::options::{ConversionMode, ConversionOptions};
let html = "<nav>menu</nav><h1>Hello</h1>";
let mut opts = ConversionOptions::for_mode(ConversionMode::Minimal);
opts.drop_interactive_shell = true;
let md = html_to_markdown_with(html, &opts);
// "# Hello\n"
Add to a Node.js project
npm install mdka
Prebuilt bindings are published for six platforms: Linux on x64 and arm64 (each with glibc and musl), macOS Apple Silicon, and Windows x64. macOS Intel and Windows ARM are not supported; the installation page lists what does work there.
const { htmlToMarkdown, htmlToMarkdownWithAsync } = require('mdka')
const md = htmlToMarkdown('<h1>Hello</h1>')
// "# Hello\n"
async function main() {
const html = '<nav>menu</nav><h1>Hello</h1>'
const minimal = await htmlToMarkdownWithAsync(html, {
mode: 'minimal',
dropInteractiveShell: true,
})
console.log(minimal)
}
main()
The Async functions cannot emit deprecation warnings, so an option that has been
deprecated is reported only by the synchronous form (htmlToMarkdownWith). See
Usage — Node.js.
Add to a Python project
pip install mdka
import mdka
md = mdka.html_to_markdown('<h1>Hello</h1>')
# "# Hello\n"
html = '<nav>menu</nav><h1>Hello</h1>'
minimal = mdka.html_to_markdown_with(
html,
mode=mdka.ConversionMode.Minimal,
drop_interactive_shell=True,
)
Conversion Modes
| Mode | Use when |
|---|---|
Balanced |
General use — the default |
Minimal |
LLM input, text extraction — the only mode that converts differently |
Strict, Semantic, Preserve |
Deprecated since 2.8.0, removed in 3.0. Aliases of Balanced; use Balanced |
Balanced, Strict, Semantic and Preserve produce identical output, and
cannot differ. They vary only in the defaults of options that have no effect
on Markdown — the format has no syntax for HTML attributes or wrapper elements —
so there is no mechanism by which they could diverge. Choosing between them
changes nothing, so the three aliases are deprecated: naming one emits a warning
(Rust, Node.js, Python, CLI) and they are removed in 3.0. See
Conversion Modes
for the full explanation.
Tables convert to GFM tables. Column alignment is carried over, | in a
cell is escaped, colspan/rowspan are expanded, and a cell holding block
content is flattened (paragraphs join with <br>, a list becomes
- one<br>- two). Four shapes have no Markdown expression and fall back to
one paragraph per cell rather than a broken table: more than one header row,
<th> used as each row's first cell, a nested <table>, and a <caption>.
No table welds its cells together on either path. See
Supported Elements for the
full list of what is and is not supported.
Learn More
Full documentation is published as GitHub Pages, and its source lives in
docs/.
https://nabbisen.github.io/mdka-rs/
| Topic | Link |
|---|---|
| Installation | /getting-started/installation |
| Rust Usage & Examples | /getting-started/usage-rust |
| Node.js Usage | /getting-started/usage-nodejs |
| Python Usage | /getting-started/usage-python |
| CLI Reference | /getting-started/usage-cli |
| API Reference | /api/index |
| Conversion Modes | /api/modes |
| ConversionOptions | /api/options |
| Supported Elements | /api/elements |
| Design Philosophy | /design/philosophy |
| Performance Characteristics | /design/performance-characteristics |
| Architecture | /design/architecture |
| Features | /design/features |
| Changelog | CHANGELOG.md |
| Roadmap | ROADMAP.md |
Open-source, with care
This project is lovingly built and maintained by volunteers.
We hope it helps streamline your work.
Please understand that the project has its own direction — while we welcome feedback, it might not fit every edge case 🌱
Acknowledgements
Depends on scraper (+ html5ever), ego-tree, rayon, thiserror.
Also, napi-rs on binding for Node.js and PyO3's pyo3 / maturin on bindings for Python.
Release files for mdka 2.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mdka-2.8.0.tar.gz | 1.1 MB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| mdka-2.8.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| mdka-2.8.0-cp310-abi3-musllinux_1_2_x86_64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ x86-64 | Details |
| mdka-2.8.0-cp310-abi3-musllinux_1_2_aarch64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ ARM64 | Details |
| mdka-2.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| mdka-2.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| mdka-2.8.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 5.2 MB
Release files / mdka-2.8.0.tar.gz
| Download URL | mdka-2.8.0.tar.gz |
|---|---|
| Size | 1.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
57c5aeb6d82130ed5922b4c3a02f3c2aadd90d0ea9239ba3f126e1d19e699715
|
|
BLAKE2b-256 checksum How to use checksums |
d62452a32327a35947a1ec99a3e1c5d2b7ac9795721b81fe8fe0dc7c89fe8e88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / mdka-2.8.0-cp310-abi3-win_amd64.whl
| Download URL | mdka-2.8.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 537.9 kB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
a782b86043c3e6576eba497a797281a280c4221a8abd41ab27ff25886aff41ae
|
|
BLAKE2b-256 checksum How to use checksums |
5eff4181e2fbaec579f0770019eb808574ce0c8b251ddb8beb41d116f20ec52b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / mdka-2.8.0-cp310-abi3-musllinux_1_2_x86_64.whl
| Download URL | mdka-2.8.0-cp310-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 872.4 kB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
17db71fd31f2a9f1b8ee9dfa5ab43dad0f9328d9fcf6c6a03b634a7fa20353fb
|
|
BLAKE2b-256 checksum How to use checksums |
1affc9743620c46adf817c23fa43c515525c0e2641b3f5ef997f8d369f79022b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / mdka-2.8.0-cp310-abi3-musllinux_1_2_aarch64.whl
| Download URL | mdka-2.8.0-cp310-abi3-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 818.2 kB |
| Tags | CPython 3.10 Linux musl 1.2+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
8a10f3d026850f3d4943a9555142e0a565485e5bd31268cb079711aa64fa8290
|
|
BLAKE2b-256 checksum How to use checksums |
7815d72a07895dd3679436a75765fd54ad74e9114bb71ae288fe0bd023431b70
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / mdka-2.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | mdka-2.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 637.4 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
b55c2c975295f249fa509f41ec01204a475c8546ae59c6234002ac7c7e163098
|
|
BLAKE2b-256 checksum How to use checksums |
68b3e9cd22bd77df342a5d44b3dadd55846594de41b24eab40b72fb3e9469c00
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / mdka-2.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | mdka-2.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 638.6 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
ee1fe93cce3fc1bc3d798e5e4ca4bd884ae2047940e8ac2298a0333e6beea4a1
|
|
BLAKE2b-256 checksum How to use checksums |
b45ca4274bab76823c0d005e026fa21ddbf4da6a276626a84bf123764089673b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / mdka-2.8.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | mdka-2.8.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 571.9 kB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
84b09137ae5d5b252b29f71286a30dd3104662d3333c15f47f844b14ce98a159
|
|
BLAKE2b-256 checksum How to use checksums |
22e91022f93687730531f446bed859638ef430cfbd41e5055407ae645d6dcc01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|