Fast Markdown parser written in Rust with zero third-party parsing dependencies. Outputs HTML, plain text, AST, ANSI terminal, Markdown, or MDX compiled to JSX, with plugins for Vite, esbuild, Rollup, webpack and Astro. Fully compliant with CommonMark 0.31.2 (652/652 spec tests pass). Available as a Rust crate and as an npm package via WebAssembly.
npm install ironmark # Node, Bun and browsers (WebAssembly)
cargo add ironmark # Rustimport ironmark from "ironmark";
const doc = ironmark.parse("# Hello\n\n**World**");
doc.html(); // "<h1>Hello</h1>\n<p><strong>World</strong></p>\n"
doc.text(); // "Hello\n\nWorld"
doc.headings(); // [{ level: 1, text: "Hello", id: "hello" }]
doc.ast(); // { Document: { children: [...] } }A document renders nothing until you ask for an output, and computes each output once. Every output also has a plain function (markdownToHtml, markdownToAst and so on). In the browser, await ironmark.ready once before the first call.
use ironmark::{render_html, ParseOptions};
let html = render_html("# Hello\n\n**World**\n", &ParseOptions::default());
assert_eq!(html, "<h1>Hello</h1>\n<p><strong>World</strong></p>\n");
// Untrusted input: escape raw HTML and cap the input size.
let safe = render_html("<script>alert(1)</script>", &ParseOptions {
disable_raw_html: true,
max_input_size: 1_000_000,
..Default::default()
});- Documents: parse once, then ask for HTML, text, AST, headings, links, front matter or ANSI.
- HTML with heading ids, and plain text for search indexes and LLM prompts.
- AST that renders back to Markdown.
- Terminal output with colours, wrapping and line numbers.
- HTML to Markdown conversion.
- MDX and plain Markdown compiled to JSX, with
@mdx-js/mdx-style components. - Extensions, on by default: tables, task lists, strikethrough, highlight, underline, autolinks and more. See options and presets.
- Security: dangerous URLs are always stripped. Raw HTML escaping, nesting limits and input size limits handle untrusted input.
- Small bundles: subpath imports such as
ironmark/htmlload only the binary they need. - Rust API with Cargo features, plus a C API.
Not sure where to start? Which function should I use? maps common goals to functions. Upgrading from 2.x? See the migration guide.
Import .md and .mdx files as components. .mdx files compile as MDX. .md files compile as plain Markdown and also export html, headings and frontmatter.
// vite.config.ts
import ironmark from "ironmark/vite";
export default { plugins: [ironmark()] };import Guide from "./guide.mdx";
import Readme, { headings } from "./README.md";
<Guide components={{ h1: Title }} />;| Import | Use it in | Guide |
|---|---|---|
ironmark/vite |
Vite, SvelteKit, Nuxt, Vitest, Storybook | Vite |
ironmark/esbuild |
esbuild, Bun.build(), Bun.plugin(), tsup |
esbuild |
ironmark/rollup |
Rollup, Rolldown | Rollup |
ironmark/webpack |
webpack 5, Rspack | webpack |
ironmark/astro |
Astro with @astrojs/react or /preact |
Astro |
All plugins share the same options.
npx ironmark --format ansi README.md # via npm
cargo install ironmark --features cli # native binaryFormats are html (default), ansi and ast. See the CLI docs for every flag.
ironmark is compared with pulldown-cmark, comrak, markdown-it, markdown-rs, md4c, markdown-wasm, md4w, marked and Bun's built-in parser, all on the same feature set. See the latest results and how to run them.
pnpm setup:wasm && pnpm build # build the WASM package
cargo test --offline # Rust tests, including the CommonMark spec
pnpm test:wasm # JS testsMore in the development guide.