Markdown to HTML: 3 methods compared (in-browser, CLI, library)
Three practical ways to convert Markdown to HTML — a web tool, a command-line one-liner, and library options for Node, Python, and Ruby. With sanitization gotchas.
Most static-site generators, blog engines, content APIs, and email tools accept HTML, not Markdown. So you write in Markdown - for the speed and readability - and convert to HTML at the boundary. This guide covers three practical ways to convert Markdown to HTML in 2026, with the gotchas that bite people in production.
The three methods
- Web tool - paste Markdown, copy HTML (or download). Zero install.
- Command line -
pandoc,cmark, ormarkdown-itCLI. Scriptable. - Library in your stack - Node (
markdown-it,marked,remark), Python (markdown,mistune), Ruby (redcarpet,kramdown), Rust (pulldown-cmark), etc.
Pick by what you're trying to do.
Method 1: Web tool
Paste Markdown into Markdown Tidy's editor - the preview pane shows the rendered HTML, Export → HTML downloads a standalone .html file you can drop into a web page or open in a browser.
Wins: zero install, the source is automatically cleaned and repaired before rendering (no AI-generated ** artifacts in your output), runs locally in your browser. Best for one-off conversions or when you just need the rendered HTML for an email or a simple webpage.
Loses: not a programmatic pipeline. If you're converting 1000 files, the CLI or a library wins.
Method 2: Command line
The fastest one-liner if Pandoc is installed:
pandoc input.md -o output.html
By default, Pandoc emits a standalone HTML document with <html>, <head>, and <body>. To get just the body fragment (useful for embedding in a CMS):
pandoc input.md -t html --no-highlight
cmark (the CommonMark reference implementation) is lighter:
cmark input.md
Outputs HTML to stdout. Pipe it into a file:
cmark input.md > output.html
For GitHub Flavored Markdown (tables, task lists, strikethrough), use cmark-gfm:
cmark-gfm --extension table --extension tasklist --extension strikethrough input.md
Method 3: Library
Node.js
markdown-it is the de-facto choice. Fast, plugin ecosystem, used by Vue's docs and many other projects:
import MarkdownIt from 'markdown-it';
const md = new MarkdownIt();
const html = md.render('# Hello world');
Alternatives: marked (smaller, slightly faster, fewer plugins) and remark (the unified ecosystem - more power, more setup).
Python
The standard library is markdown:
import markdown
html = markdown.markdown('# Hello world')
For GFM features (tables, fenced code, etc.) enable extensions:
html = markdown.markdown(text, extensions=['tables', 'fenced_code'])
For speed at scale, mistune is faster but a smaller plugin ecosystem. See Markdown in Python for the full comparison.
React / JSX
react-markdown renders Markdown as React components - no dangerouslySetInnerHTML, safer by default:
import ReactMarkdown from 'react-markdown';
<ReactMarkdown>{markdown}</ReactMarkdown>;
See Markdown in React for the full picture (sanitization, custom renderers, code highlighting).
Ruby
kramdown is the de-facto standard for Ruby (used by Jekyll, Middleman, GitHub Pages historically):
require 'kramdown'
html = Kramdown::Document.new(text).to_html
Sanitization: the bit everyone forgets
This is the most-important paragraph in this guide. Most Markdown libraries do not sanitize HTML by default. If your Markdown source contains:
Some text.
<script>alert('xss')</script>
…most libraries pass that <script> tag through to the output. If that HTML ends up rendered in another user's browser, you have an XSS vulnerability.
Rules:
- Sanitize after rendering. Use DOMPurify (Node/browser) or
bleach(Python) on the output HTML before storing or displaying. - Configure the renderer to refuse raw HTML.
markdown-ithas{ html: false }.markedhassanitize: false- confusingly named, but the right setting is not allowing raw HTML at all via themarkdown.htmloption. - Don't trust the source. Even if you "wrote" the Markdown, if a user can submit Markdown that becomes part of an HTML page, sanitize.
Markdown Tidy's renderer defaults to refusing raw HTML in persisted output. Same goes for our public API.
GitHub Flavored vs CommonMark
Pure CommonMark doesn't include tables, task lists, strikethrough, or auto-linked URLs. If you write Markdown that includes any of those, you need a GFM-compatible renderer. See GitHub Flavored Markdown: what's different.
Most modern libraries support GFM via opt-in extensions; check the docs for tables, tasklist, strikethrough, autolink, and linkify.
Quick picker
| Your situation | Pick |
|---|---|
| One-off conversion, no install | Markdown Tidy → Export → HTML |
| Convert one file in your terminal | pandoc or cmark-gfm |
| Render in a Node app | markdown-it |
| Render in a Python app | markdown (extensions enabled) |
| Render in React | react-markdown |
| Render server-side in Ruby | kramdown |
| Heavy programmatic load, no install | Markdown Tidy API - POST markdown, get HTML |
Related
- Markdown to PDF - when HTML isn't the destination
- Markdown to Word (.docx) - when stakeholders demand editable Word files
- Markdown in React - the React-specific deep dive
- Markdown in Python - the Python-specific deep dive
Related articles
How to repair broken Markdown tables in 30 seconds
AI-generated Markdown tables almost always look fine in chat and break when you export them. Here's exactly what goes wrong, and the fastest way to repair them.
Confluence and Markdown: how to import, convert, and sync
Confluence doesn't accept Markdown directly in its editor. Three working ways to get Markdown into Confluence — paste-conversion, the macro, and the bulk import.
Markdown viewer: how to view .md files online and offline
The best Markdown viewers for browsers, mobile, and desktop. From quick previews of a single .md file to full multi-document workspaces.
Markdown in Discord: complete formatting guide (2026)
Every Markdown trick that works in Discord — bold, italic, headings, code blocks, spoilers, lists, and the syntax Discord supports that Markdown doesn't.