marked vs markdown-it vs turndown vs showdown vs node-html-markdown
Markdown and HTML Conversion Libraries for JavaScript
markedmarkdown-itturndownshowdownnode-html-markdownSimilar Packages:

Markdown and HTML Conversion Libraries for JavaScript

markdown-it, marked, and showdown are libraries that convert Markdown text into HTML, enabling rich text rendering in web applications. turndown and node-html-markdown perform the reverse operation, converting HTML content back into Markdown format. These tools are essential for content management systems, comment sections, documentation sites, and any application requiring flexible text formatting or content migration.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
marked43,268,33736,854450 kB1214 days agoMIT
markdown-it22,744,49821,507777 kB209 days agoMIT
turndown4,914,24111,207192 kB1402 months agoMIT
showdown1,300,11014,863801 kB235-MIT
node-html-markdown578,642261113 kB137 months agoMIT

Markdown and HTML Conversion Libraries: Architecture and Use Cases

When building content-driven applications, you often need to transform text between Markdown and HTML. The ecosystem offers several mature tools, but they serve different directions and architectural needs. markdown-it, marked, and showdown convert Markdown to HTML. turndown and node-html-markdown convert HTML back to Markdown. Let's explore how they differ in practice.

๐Ÿ”„ Conversion Direction: Markdown to HTML vs HTML to Markdown

The most critical distinction is the direction of conversion. Using the wrong tool for the direction will break your workflow.

markdown-it converts Markdown to HTML with a focus on plugins.

import MarkdownIt from 'markdown-it';
const md = new MarkdownIt();
const result = md.render('# Hello World');
// Output: <h1>Hello World</h1>

marked converts Markdown to HTML with a focus on speed.

import { marked } from 'marked';
const result = marked('# Hello World');
// Output: <h1>Hello World</h1>

showdown converts Markdown to HTML with a focus on extensions.

import { Converter } from 'showdown';
const converter = new Converter();
const result = converter.makeHtml('# Hello World');
// Output: <h1>Hello World</h1>

turndown converts HTML to Markdown, running in Node or browser.

import TurndownService from 'turndown';
const turndownService = new TurndownService();
const result = turndownService.turndown('<h1>Hello World</h1>');
// Output: # Hello World

node-html-markdown converts HTML to Markdown, optimized for Node.js.

import { NodeHtmlMarkdown } from 'node-html-markdown';
const result = NodeHtmlMarkdown.translate('<h1>Hello World</h1>');
// Output: # Hello World

๐Ÿงฉ Extensibility: Plugins vs Custom Renderers

How you customize the output varies significantly between these libraries. Some use a plugin system, while others rely on configuration objects.

markdown-it uses a token-based plugin system. You can insert rules into the parsing chain to modify how tokens are generated.

import MarkdownIt from 'markdown-it';
const md = new MarkdownIt();
md.use(require('markdown-it-emoji'));
const result = md.render(':smile:');

marked uses a renderer object or async extensions. You override methods on the renderer to change HTML output for specific elements.

import { marked } from 'marked';
const renderer = new marked.Renderer();
renderer.heading = (text, level) => `<h${level} class="custom">${text}</h${level}>`;
const result = marked('# Hello', { renderer });

showdown uses a flavor system and custom extensions. You can enable predefined flavors like 'github' or write custom language extensions.

import { Converter } from 'showdown';
const converter = new Converter({ flavor: 'github' });
const result = converter.makeHtml('# Hello');

turndown uses a rule-based system for HTML elements. You add rules to handle specific tags or classes during the HTML to Markdown conversion.

import TurndownService from 'turndown';
const turndownService = new TurndownService();
turndownService.addRule('strikethrough', {
  filter: ['del', 's', 'strike'],
  replacement: (content) => `~~${content}~~`
});

node-html-markdown uses configuration options for specific tags. It has fewer extension points but allows configuring how specific elements like images or links are handled.

import { NodeHtmlMarkdown } from 'node-html-markdown';
const result = NodeHtmlMarkdown.translate('<img src="a.jpg">', {
  ignore: ['img'] // Example config to ignore specific tags
});

๐Ÿ›ก๏ธ Security and Sanitization

Rendering user-generated HTML carries security risks like XSS. Some libraries include sanitization, while others expect you to handle it separately.

markdown-it does not sanitize HTML by default. You must pair it with a sanitizer like sanitize-html to prevent script injection.

import sanitizeHtml from 'sanitize-html';
import MarkdownIt from 'markdown-it';
const md = new MarkdownIt();
const raw = md.render(userInput);
const clean = sanitizeHtml(raw);

marked has a built-in sanitizer option but it is deprecated. The official recommendation is to use a dedicated library like dompurify for security.

import { marked } from 'marked';
import DOMPurify from 'dompurify';
const raw = marked(userInput);
const clean = DOMPurify.sanitize(raw);

showdown has a built-in sanitize option. It can strip dangerous tags directly during the conversion process without extra dependencies.

import { Converter } from 'showdown';
const converter = new Converter({ sanitize: true });
const result = converter.makeHtml(userInput);

turndown focuses on conversion, not sanitization. Since it outputs Markdown, the risk is lower, but you should still validate input HTML before conversion.

import TurndownService from 'turndown';
const turndownService = new TurndownService();
// Validate HTML string before passing to turndown
const result = turndownService.turndown(unsafeHtml);

node-html-markdown does not include sanitization features. It assumes the input HTML is trusted or has been sanitized prior to conversion in your Node.js pipeline.

import { NodeHtmlMarkdown } from 'node-html-markdown';
// Ensure htmlInput is safe before translating
const result = NodeHtmlMarkdown.translate(htmlInput);

โšก Performance and Environment

Performance matters when processing large documents or running on edge devices. Environment support (Browser vs Node) also dictates your choice.

markdown-it is highly optimized for Node and browser. It parses into tokens first, which adds a slight overhead but allows for complex transformations.

// markdown-it works in both environments
const md = new MarkdownIt();
console.log(md.render('# Test'));

marked is known for being very fast. It compiles Markdown directly to HTML strings, making it efficient for high-volume rendering.

// marked is lightweight and fast
console.log(marked('# Test'));

showdown is slightly heavier due to its extension system. It works well in browsers but may be slower than marked on large documents.

// showdown is versatile but can be slower
const converter = new Converter();
console.log(converter.makeHtml('# Test'));

turndown relies on DOM parsing in the browser. In Node.js, it requires a DOM implementation like jsdom to function correctly.

// turndown needs a DOM in Node.js
// const { JSDOM } = require('jsdom');
// global.window = new JSDOM('').window;
const turndownService = new TurndownService();

node-html-markdown is built specifically for Node.js. It does not rely on a virtual DOM, making it faster and lighter for server-side scripts.

// node-html-markdown is Node-only
const result = NodeHtmlMarkdown.translate('<h1>Test</h1>');

๐ŸŒฑ Similarities: Shared Ground

Despite their differences, these libraries share common goals and patterns.

1. ๐Ÿ“ Standard Markdown Support

  • All support core CommonMark or GitHub Flavored Markdown.
  • Basic syntax like headers, lists, and links works out of the box.
// All handle basic syntax similarly
// markdown-it
md.render('- item'); 
// marked
marked('- item');
// showdown
converter.makeHtml('- item');

2. ๐Ÿ”Œ Customization Capabilities

  • Each allows some form of output modification.
  • Developers can tweak how specific elements render.
// All allow some config
// markdown-it: md.set({ html: true })
// marked: marked.setOptions({ breaks: true })
// showdown: new Converter({ tables: true })

3. ๐ŸŒ Open Source Ecosystem

  • All are maintained by community contributors.
  • Plugins and extensions exist for all major use cases.
// Ecosystem examples
// markdown-it: markdown-it-container
// marked: marked-highlight
// turndown: turndown-plugin-gfm

๐Ÿ“Š Summary: Key Differences

Featuremarkdown-itmarkedshowdownturndownnode-html-markdown
DirectionMD โ†’ HTMLMD โ†’ HTMLMD โ†’ HTMLHTML โ†’ MDHTML โ†’ MD
ExtensibilityPlugin SystemRenderer OverrideExtensionsRule SystemConfig Options
SanitizationExternal RequiredExternal RecommendedBuilt-in OptionNoneNone
EnvironmentNode & BrowserNode & BrowserNode & BrowserNode & BrowserNode Only
Primary UseComplex DocsFast RenderingLegacy/ExtensionsContent EditorsServer Scripts

๐Ÿ’ก The Big Picture

markdown-it is the choice for complex documentation systems. Its plugin architecture allows you to build custom content experiences, but it requires more setup to secure properly.

marked is the workhorse for general-purpose rendering. If you need to display comments or blog posts quickly and safely, pair this with a sanitizer and move on.

showdown remains useful for legacy systems or specific extension needs. For new greenfield projects, marked or markdown-it usually offer better long-term support.

turndown is the standard for HTML to Markdown conversion. If you are building a rich-text editor that exports to Markdown, this is the most reliable option across environments.

node-html-markdown is a niche tool for server-side Node.js scripts. Use it when you need to process HTML files in a build pipeline without the overhead of a DOM implementation.

Final Thought: Direction matters most. Pick markdown-it or marked for displaying content. Pick turndown for editing or migrating content. Always sanitize HTML output when rendering user input to keep your application secure.

How to Choose: marked vs markdown-it vs turndown vs showdown vs node-html-markdown

  • marked:

    Choose marked if you prioritize speed and simplicity without sacrificing essential features. It is a solid default for rendering user-generated content where performance matters. Recent versions support async rendering, which helps when integrating with asynchronous highlighters or custom renderers.

  • markdown-it:

    Choose markdown-it if you need a highly extensible parser with a robust plugin ecosystem. It is ideal for projects requiring strict CommonMark compliance or custom syntax rules. Its architecture allows deep customization of the token stream, making it suitable for complex documentation platforms.

  • turndown:

    Choose turndown if you need to convert HTML to Markdown in the browser or Node.js with high fidelity. It is the standard choice for content editors that allow switching between rich text and Markdown sources. It handles complex DOM structures well and supports custom rules.

  • showdown:

    Choose showdown if you are maintaining a legacy project that already depends on it or need specific older extensions. For new projects, consider modern alternatives, as its development pace is slower compared to marked or markdown-it. It remains viable for simple client-side rendering tasks.

  • node-html-markdown:

    Choose node-html-markdown if you are working exclusively in a Node.js environment and need a lightweight HTML to Markdown converter. It is optimized for server-side processing where browser DOM APIs are unavailable. It is less flexible than turndown but requires fewer dependencies.

README for marked

Marked

npm install size downloads github actions snyk

  • โšก built for speed
  • โฌ‡๏ธ low-level compiler for parsing markdown without caching or blocking for long periods of time
  • โš–๏ธ light-weight while implementing all markdown features from the supported flavors & specifications
  • ๐ŸŒ works in a browser, on a server, or from a command line interface (CLI)

Demo

Check out the demo page to see Marked in action โ›น๏ธ

Docs

Our documentation pages are also rendered using marked ๐Ÿ’ฏ

Also read about:

Compatibility

Node.js: Only current and LTS Node.js versions are supported. End of life Node.js versions may become incompatible with Marked at any point in time.

Browser: Baseline Widely Available

Installation

CLI:

npm install -g marked

In-browser:

npm install marked

Usage

Warning: ๐Ÿšจ Marked does not sanitize the output HTML. Please use a sanitize library, like DOMPurify (recommended), sanitize-html or insane on the output HTML! ๐Ÿšจ

DOMPurify.sanitize(marked.parse(`<img src="https://raw.githubusercontent.com/markedjs/marked/HEAD/x" onerror="alert('not happening')">`));

CLI

# Example with stdin input
$ marked -o hello.html
hello world
^D
$ cat hello.html
<p>hello world</p>
# Print all options
$ marked --help

Browser

<!doctype html>
<html>
<head>
  <meta charset="utf-8"/>
  <title>Marked in the browser</title>
</head>
<body>
  <div id="content"></div>
  <script src="https://cdn.jsdelivr.net/npm/marked/lib/marked.umd.js"></script>
  <script>
    document.getElementById('content').innerHTML =
      marked.parse('# Marked in the browser\n\nRendered by **marked**.');
  </script>
</body>
</html>

or import esm module

<script type="module">
  import { marked } from "https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js";
  document.getElementById('content').innerHTML =
    marked.parse('# Marked in the browser\n\nRendered by **marked**.');
</script>

License

Copyright (c) 2018+, MarkedJS. (MIT License) Copyright (c) 2011-2018, Christopher Jeffrey. (MIT License)