remark is built around markdown as structured data — it parses, transforms, and serializes markdown through a pipeline of plugins. Producing HTML is not part of remark itself; instead, you bridge into the rehype ecosystem usingDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/remarkjs/remark/llms.txt
Use this file to discover all available pages before exploring further.
remark-rehype, then serialize the resulting HTML syntax tree with rehype-stringify. This separation keeps each concern focused while giving you full control over every step of the transformation.
How the pipeline works
The unified processor chains plugins together. For markdown-to-HTML, the data flows through four stages:remark-parsereads your markdown string and produces an mdast (Markdown Abstract Syntax Tree).remark-rehypeconverts the mdast into an hast (HTML Abstract Syntax Tree).rehype-sanitizewalks the hast and removes any nodes or attributes that could be used for cross-site scripting (XSS).rehype-stringifyserializes the cleaned hast into an HTML string.
import rehypeSanitize from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import {unified} from 'unified'
const file = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeSanitize)
.use(rehypeStringify)
.process('# Hello, Neptune!')
console.log(String(file))
remark supports CommonMark by default. To handle GitHub Flavored Markdown (autolink literals, footnotes, strikethrough, tables, tasklists) and YAML frontmatter, add the corresponding plugins. Install the additional packages first:
import rehypeStringify from 'rehype-stringify'
import remarkFrontmatter from 'remark-frontmatter'
import remarkGfm from 'remark-gfm'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import {unified} from 'unified'
const value = `---
layout: solar-system
---
# Hi ~~Mars~~Venus!
`
const file = await unified()
.use(remarkParse)
.use(remarkFrontmatter)
.use(remarkGfm)
.use(remarkRehype)
.use(rehypeStringify)
.process(value)
console.log(String(file))
Why sanitization matters
When you convert markdown to HTML, any raw HTML that appears inside the markdown source is preserved by default. This means a malicious author could embed<script> tags, dangerous javascript: URLs in links, or event handlers like onerror in image tags. All of these are vectors for cross-site scripting (XSS) attacks.
rehype-sanitize solves this by traversing the hast and stripping elements and attributes that are not on its allowlist. The default schema follows GitHub’s sanitization rules, which is a sensible baseline for most applications. You can also pass a custom schema if your use case requires specific HTML elements to remain.
Using the remark shorthand
When both input and output are markdown, the remark package is a convenient shorthand for unified().use(remarkParse).use(remarkStringify). For markdown-to-HTML pipelines, however, you should use unified directly and compose the full chain as shown above, since the output format changes from markdown to HTML.
Next steps
Extensions
Add GFM, math, MDX, and other syntax extensions to your pipeline.
Security
Understand XSS and DDoS risks when processing untrusted markdown.