Bun.markdown: A Lightning-Fast CommonMark Parser Built for the Modern Web
Introduced in Bun v1.3.8 (January 29, 2026), Bun.markdown is a blazing-fast, CommonMark-compliant markdown parser built directly into the Bun runtime. Written in Zig as a port of the popular md4c library, it offers three distinct rendering methods to handle virtually any markdown use case—from simple HTML generation to full React component rendering.
Why Built-in Markdown Parsing Matters
Before Bun v1.3.8, developers working with markdown in Bun had to rely on external libraries like marked, markdown-it, or remark. While these libraries are excellent, they come with trade-offs:
- Additional dependencies to install and maintain
- Bundle size overhead when bundling for the browser
- Runtime overhead from JavaScript-based parsing
- Version conflicts across different packages in a monorepo
Bun.markdown eliminates all of these concerns by providing a native, zero-dependency solution that's compiled directly into the Bun runtime. It's fast, reliable, and always available without any setup.
Three Rendering Methods for Every Use Case
Bun.markdown provides three APIs, each designed for a specific rendering scenario:
1. Bun.markdown.html() — Direct HTML Rendering
The simplest way to convert markdown to HTML. Perfect for server-side rendering, static site generation, or any scenario where you need HTML output.
import { Bun } from "bun";
const html = Bun.markdown.html("# Hello **world**");
// Output: "<h1>Hello <strong>world</strong></h1>\n"
// With automatic heading IDs
const htmlWithIds = Bun.markdown.html("## Hello", { headingIds: true });
// Output: '<h2 id="hello">Hello</h2>\n'
The headingIds option automatically generates id attributes for headings based on their text content, making them anchor-link friendly without any additional processing.
2. Bun.markdown.render() — Custom Callback Rendering
For maximum flexibility, render() lets you provide custom JavaScript callbacks for each markdown element type. This enables custom HTML output, ANSI terminal rendering, or virtually any text-based format.
// Custom HTML with CSS classes
const html = Bun.markdown.render("# Title\n\nHello **world**", {
heading: (children, { level }) => `<h${level} class="title">${children}</h${level}>`,
strong: (children) => `<b>${children}</b>`,
paragraph: (children) => `<p class="content">${children}</p>`,
});
// ANSI terminal output for CLI tools
const ansi = Bun.markdown.render("# Hello\n\n**bold** and ~~strikethrough~~", {
heading: (children) => `\x1b[1;4m${children}\x1b[0m\n`,
strong: (children) => `\x1b[1m${children}\x1b[22m`,
strikethrough: (children) => `\x1b[9m${children}\x1b[29m`,
code: (children) => `\x1b[36m${children}\x1b[39m`,
});
console.log(ansi); // Renders colored terminal output
This approach is particularly useful for:
- CLI tools that need rich text formatting
- Custom HTML generation with specific classes or attributes
- Non-HTML output formats (LaTeX, AsciiDoc, etc.)
- Security-conscious rendering that strips dangerous elements
3. Bun.markdown.react() — Direct React Component Rendering
The most powerful option for Bun-based frontend applications. react() returns a React Fragment containing the parsed markdown as React elements, complete with automatic component mapping.
import { Bun } from "bun";
import React from "react";
function Markdown({ text }: { text: string }) {
return Bun.markdown.react(text);
}
// With custom components
const element = Bun.markdown.react("# Hello\n\n[A link](https://example.com)", {
h1: ({ children }) => <h1 className="title">{children}</h1>,
a: ({ children, href }) => <a href={href} className="link" target="_blank">{children}</a>,
});
Component mapping lets you replace standard HTML elements with your own React components:
const CustomReact = Bun.markdown.react("", {
img: ({ src, alt }) => (
<LazyImage src={src} alt={alt} placeholder="/loading.png" />
),
code: ({ children }) => (
<SyntaxHighlighter language="javascript">{children}</SyntaxHighlighter>
),
});
This approach eliminates the need for separate markdown parsing libraries in React applications and provides seamless integration with your existing component ecosystem.
GitHub Flavored Markdown (GFM) Support
Bun.markdown includes full GitHub Flavored Markdown support out of the box. These extensions are the ones developers use daily, and they're enabled by default without any configuration:
const gfm = Bun.markdown.html(`
| Name | Type | Description |
|------|------|-------------|
| id | number | Unique identifier |
| name | string | Display name |
- [x] Completed task
- [ ] Pending task
~~Deleted text~~
`);
Supported GFM features:
- Tables — Full support for pipe-separated tables with alignment
- Strikethrough —
~~deleted~~syntax - Task lists —
- [x]syntax for checkboxes - Permissive autolinks — URLs without angle brackets
Additional Configuration Options
Beyond GFM, Bun.markdown supports several additional options:
const markdown = Bun.markdown.html("Some [[WikiLink]] and $E=mc^2$", {
wikiLinks: true, // Enable [[WikiLink]] syntax
latexMath: true, // Enable $...$ LaTeX math
headingIds: true, // Auto-generate heading IDs
autolinkHeadings: true, // Auto-link headings to themselves
});
These options make Bun.markdown suitable for diverse use cases:
- Wiki-style documentation with
wikiLinks - Technical documentation with mathematical formulas via
latexMath - Documentation sites with auto-anchored headings
Performance Improvements in Bun v1.3.9
Bun v1.3.9 (February 8, 2026) brought significant performance improvements to Bun.markdown, making it even faster:
| Optimization | Impact |
|---|---|
| SIMD-accelerated HTML escaping | HTML rendering 3-15% faster |
| React rendering cache | 28% faster for small inputs, 7-7.4% for medium/large |
| Memory efficiency | 40% fewer string objects, 6% less heap usage |
The React rendering improvements are particularly noteworthy. By caching HTML tag strings, Bun.markdown.react() avoids repeated allocations, resulting in substantial performance gains—especially for small markdown fragments commonly used in UI components.
Real-World Use Cases
Static Site Generator
import { Bun } from "bun";
async function buildSite() {
const files = Bun.glob("content/**/*.md");
for (const file of files) {
const content = await Bun.file(file).text();
const html = Bun.markdown.html(content, { headingIds: true });
await Bun.write(`dist/${file.replace('content/', '').replace('.md', '.html')}`, `
<!DOCTYPE html>
<html>
<head><title>My Site</title></head>
<body>${html}</body>
</html>
`);
}
}
buildSite();
CLI Documentation Viewer
#!/usr/bin/env bun
import { Bun } from "bun";
const doc = await Bun.read(process.argv[2] || "README.md").text();
const ansi = Bun.markdown.render(doc, {
heading: (children) => `\x1b[1;4m${children}\x1b[0m\n`,
strong: (children) => `\x1b[1m${children}\x1b[22m`,
code: (children) => `\x1b[36m${children}\x1b[39m`,
link: (children, { href }) => `\x1b[34;4m${children}\x1b[0m (${href})`,
});
console.log(ansi);
React Blog Component
import { Bun } from "bun";
import React from "react";
interface BlogPostProps {
content: string;
}
export default function BlogPost({ content }: BlogPostProps) {
return Bun.markdown.react(content, {
h1: ({ children }) => <h1 className="text-3xl font-bold mb-4">{children}</h1>,
h2: ({ children }) => <h2 className="text-2xl font-semibold mb-3 mt-6">{children}</h2>,
p: ({ children }) => <p className="mb-4 leading-relaxed">{children}</p>,
code: ({ children }) => (
<code className="bg-gray-100 px-1 py-0.5 rounded text-sm">{children}</code>
),
pre: ({ children }) => (
<pre className="bg-gray-900 text-green-400 p-4 rounded-lg overflow-x-auto mb-4">
{children}
</pre>
),
img: ({ src, alt }) => (
<img src={src} alt={alt} className="rounded-lg shadow-lg my-4" />
),
});
}
Comparison with External Libraries
| Feature | Bun.markdown | marked | markdown-it |
|---|---|---|---|
| Zero dependencies | ✅ Built-in | ❌ npm package | ❌ npm package |
| CommonMark compliant | ✅ | ✅ | ✅ |
| GFM support | ✅ Built-in | ⚠️ Requires plugin | ⚠️ Requires plugin |
| React rendering | ✅ Native | ❌ Requires separate lib | ❌ Requires separate lib |
| Custom callbacks | ✅ | ⚠️ Limited | ⚠️ Requires plugins |
| Bundle impact | ✅ Zero | ❌ ~30KB gzipped | ❌ ~50KB gzipped |
| Performance | ⚡ Fast | ⚡ Fast | ⚡ Fast |
While external libraries offer extensive plugin ecosystems, Bun.markdown covers the most common use cases without any overhead—making it an excellent default choice for Bun projects.
Getting Started
Bun.markdown is available immediately with Bun v1.3.8 or later. No installation required:
# Upgrade to the latest Bun
bun upgrade
# Or install via npm
npm install -g bun
Then use it directly:
import { Bun } from "bun";
const html = Bun.markdown.html("# Hello world");
console.log(html);
Conclusion
Bun.markdown represents Bun's philosophy of providing fast, zero-dependency tools built directly into the runtime. With three rendering methods, GFM support, and continuous performance improvements, it's ready for production use in everything from simple scripts to complex React applications.
For more details, check out the official Bun.markdown documentation and the v1.3.8 release notes.