Skip to main content

Documentation 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 does not stand alone — it is one piece of a larger content-processing ecosystem called unified. Understanding how these layers fit together helps you make the most of remark’s plugin architecture and know when to reach for each tool.

unified: the shared core

unified is the core project that transforms content using abstract syntax trees (ASTs). On its own, unified is an interface without opinions about any particular format. It knows how to run a pipeline of plugins, carry a virtual file through that pipeline, and produce output — but it relies on format-specific plugins to do the actual parsing and serializing. remark adds markdown support to unified. When you install remark-parse, unified gains the ability to read markdown and produce a syntax tree. When you install remark-stringify, unified gains the ability to serialize that tree back into markdown.
The remark package is a convenience shortcut for unified().use(remarkParse).use(remarkStringify). Use it when both your input and output are markdown. When you need to convert markdown to HTML or another format, compose the pipeline yourself with unified directly.

The three main processing ecosystems

The unified collective maintains three major ecosystems, each targeting a different content domain:

remark

Processes markdown. Uses the mdast syntax tree. The world’s most popular markdown parser, with 150+ plugins.

rehype

Processes HTML. Uses the hast (hypertext abstract syntax tree) spec. Commonly used as the final step when converting markdown to HTML.

retext

Processes natural language. Uses the nlcst spec. Useful for prose analysis, readability checks, and spell-checking.
These ecosystems are designed to interoperate. A bridge plugin like remark-rehype converts a remark mdast tree into a rehype hast tree, letting you apply HTML-level transformations after markdown-level ones — all within a single unified pipeline.

mdast: the markdown syntax tree

Every remark pipeline works through an intermediate representation called mdast (markdown abstract syntax tree). mdast is a specification — maintained at github.com/syntax-tree/mdast — that describes how markdown constructs are represented as JSON objects. When remark-parse processes your markdown source, it produces an mdast tree. Plugins then receive and can modify that tree. When remark-stringify (or rehype-stringify after a conversion) runs, it serializes the final tree into the output format. The source file is never manipulated as a raw string — only the structured tree is.

The parse → transform → stringify pipeline

Every unified processor follows the same three-phase pattern:
1

Parse

A parser plugin reads the input (a string or buffer) and produces a syntax tree. For markdown, remark-parse uses micromark under the hood to build a fully spec-compliant mdast tree.
2

Transform

Each transformer plugin receives the tree (and the vfile) in turn. Plugins can inspect, modify, replace, or add nodes. This is where most of the interesting work happens — linting, generating a table of contents, converting between tree formats, and so on.
3

Stringify

A compiler plugin converts the final tree back into a string. For markdown output, remark-stringify serializes the mdast. For HTML, rehype-stringify serializes the hast.

Composing a cross-ecosystem pipeline

The .use() method attaches plugins to a processor in order. Plugins are applied during the matching phase — parsers at parse time, compilers at stringify time, and everything else as transformers. The following example converts markdown to HTML by chaining remark and rehype together:
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(rehypeStringify)
  .process('# Hello, *Mercury*!')

console.log(String(file)) // => '<h1>Hello, <em>Mercury</em>!</h1>'
remarkParse sets up the parser, remarkRehype is a transformer that converts the entire mdast tree into a hast tree, and rehypeStringify sets up the compiler for the hast side. Only one parser and one compiler can be active at a time, but any number of transformers can be chained between them.
For full details on the .use() API — including how to pass options to plugins and how the processor lifecycle works — see the unified documentation.

vfile: the virtual file

Throughout the pipeline, content is carried inside a vfile (virtual file). A vfile is a lightweight object that holds:
  • The value — the raw content string or buffer at the start, updated to the serialized output at the end.
  • The path and history — where the file came from (useful for error messages and relative URL resolution).
  • A messages array — warnings and errors written by plugins such as remark-lint. Each message records a source position, a reason, and a severity level.
  • Arbitrary data — a plain object where plugins can store metadata to pass between pipeline stages.
You call String(file) on the result of .process() to extract the final serialized content, and file.messages to read any diagnostics accumulated during processing.

The full ecosystem at a glance

unified

The shared processor interface. Provides .use(), .process(), and the plugin pipeline mechanism that all remark, rehype, and retext tools are built on.

remark

Markdown processing. Includes remark-parse (markdown → mdast), remark-stringify (mdast → markdown), and the remark convenience package combining both.

mdast

The markdown AST specification. Defines every node type — headings, paragraphs, lists, links, code blocks, and more — as typed JSON objects with position information.

rehype

HTML processing. Used alongside remark when markdown-to-HTML conversion is needed. remark-rehype is the bridge between the two ecosystems.

Build docs developers (and LLMs) love