Parsing Markdown Natively with Bun
If you’ve ever wired together unified, remark-parse, remark-rehype, and rehype-stringify just to convert a Markdown string to HTML, you know the overhead. Bun 1.3.8 (released January 2026) ships a built-in Markdown parser that replaces that entire chain with a single API call — no installs, no imports, no plugin configuration required.
Here’s what the new Bun.markdown API does, how it works, and where it fits into your workflow.
Key Takeaways
Bun.markdownis a native Markdown parser built into the Bun runtime, powered by a Zig port of the md4c C library.- The
html()method converts Markdown to HTML in a single call without requiring external libraries. render()supports custom output formats (styled HTML, ANSI, plain text) through JavaScript callbacks for each element type.react()returns React elements directly, allowing Markdown content to be rendered as part of a component tree.- The API is still marked unstable, so pin your Bun version and verify output before deploying to production.
What Is the Bun Markdown Parser?
Bun.markdown is a native Markdown parser built directly into the Bun runtime. It follows the CommonMark specification and is implemented as a Zig port of the md4c C library — a parser used in performance-sensitive environments such as Qt.
Because it runs as compiled Zig code rather than JavaScript, it avoids the overhead of JavaScript-based parsing pipelines like unified and remark. Instead of chaining multiple packages together, Bun exposes a single runtime API for Markdown processing.
Note: The
Bun.markdownAPI is currently marked as unstable in the official Bun documentation. The interface works today, but specific options and method signatures may change in future Bun releases. Check the Bun release notes before upgrading in production.
Bun Markdown to HTML: The html() Method
The simplest use case — converting Markdown to an HTML string — requires no setup:
const html = Bun.markdown.html("# Hello **world**")
// "<h1>Hello <strong>world</strong></h1>\n"
Pass options as a second argument. The headings option is useful for documentation sites and table-of-contents generation:
const html = Bun.markdown.html("## Getting Started", {
headings: { ids: true }
})
// '<h2 id="getting-started">Getting Started</h2>\n'
GitHub Flavored Markdown (GFM) extensions are enabled by default, including tables, strikethrough (~~text~~), task lists (- [x] done), and permissive autolinks. Additional options such as wikiLinks, latexMath, and heading autolinking are also supported.
Custom Rendering with Bun.markdown.render()
When you need output that isn’t standard HTML — styled markup, ANSI terminal output, or plain text — render() accepts JavaScript callbacks for each element type:
// Add CSS classes to elements
const html = Bun.markdown.render("# Title\n\nHello **world**", {
heading: (children, { level }) => `<h${level} class="title">${children}</h${level}>`,
paragraph: (children) => `<p class="body">${children}</p>`,
strong: (children) => `<b>${children}</b>`,
})
// Strip all formatting to plain text
const plain = Bun.markdown.render("# Title\n\n**bold** text", {
heading: (children) => children + "\n",
strong: (children) => children,
paragraph: (children) => children + "\n",
})
// Return null to omit specific elements entirely
const noImages = Bun.markdown.render("# Title\n\n", {
image: () => null,
heading: (children) => `<h1>${children}</h1>`,
})
This makes render() useful for CLI tools, email generation, or any pipeline where HTML isn’t the target format.
Discover how at OpenReplay.com.
Bun Markdown React Rendering with react()
Bun.markdown.react() returns React elements that can be used directly in a component tree:
function Markdown({ text }: { text: string }) {
return Bun.markdown.react(text)
}
// Map Markdown elements to custom components
const element = Bun.markdown.react("# Hello", {
h1: ({ children }) => <h1 className="page-title">{children}</h1>,
})
// Works with server-side rendering
import { renderToString } from "react-dom/server"
const html = renderToString(Bun.markdown.react("# Hello **world**"))
If you’re using React 18 or older, you can pass a compatibility option:
Bun.markdown.react(markdownText, undefined, { reactVersion: 18 })
When to Use Bun.markdown vs. Remark
| Scenario | Recommendation |
|---|---|
| Basic Markdown-to-HTML conversion | Bun.markdown.html() |
| Custom output (ANSI, styled HTML) | Bun.markdown.render() |
| React component trees | Bun.markdown.react() |
| Syntax highlighting, footnotes, complex plugins | Stick with unified/remark |
Conclusion
If you’re already running Bun 1.3.8 or later, Bun.markdown is available globally — no installation needed. Start with Bun.markdown.html() for straightforward content pipelines, and reach for render() or react() when you need more control over the output.
Given that the API is still marked unstable, pin your Bun version and test rendering output against your expected HTML before deploying to production.
FAQs
No. Bun.markdown handles standard Markdown-to-HTML conversion but does not include built-in syntax highlighting. For code highlighting, you would need to post-process the HTML output with a library like Shiki or Prism, or use a unified/remark pipeline with a dedicated highlighting plugin.
No. Bun.markdown is a native API built into the Bun runtime and is not available in Node.js. If your project runs on Node, you will need to continue using libraries like unified, remark, or markdown-it for Markdown parsing.
Bun.markdown does not include built-in HTML sanitization. If you are processing user-submitted Markdown, pass the generated HTML through a sanitization library such as DOMPurify or sanitize-html before rendering it in a browser to prevent cross-site scripting issues.
No. Bun.markdown implements CommonMark with GitHub Flavored Markdown extensions. It does not support MDX, custom directives, or the plugin ecosystem available through unified and remark. For those use cases, a remark-based pipeline remains the better choice.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.