md2rich

June 27, 2026

Satteri: Rust Markdown Pipeline for JavaScript (2026)

A new Markdown engine landed on Hacker News on June 25 2026, and it changes what a client-side Markdown editor can do without giving up the JavaScript plugin model most authors are used to. Satteri is a Rust core that parses and compiles, wrapped in a JavaScript surface where you write your plugins the same way you would write remark or rehype plugins. For paste-into-rich-text tools like md2rich, it is the most interesting Markdown engine release of the year, because it offers a path to faster, more capable in-browser conversion while keeping the developer ergonomics that make custom transformations practical.

What Satteri Is, in One Paragraph

Satteri is a Markdown and MDX processing pipeline published by the Bruits project. The maintainer works on the Astro core team, the group responsible for the content layer that powers millions of Markdown-driven websites. Satteri's claim is simple: do the expensive work (lexing, parsing into an MDAST, allocating nodes, compiling MDX to JavaScript) in Rust, then expose a typed plugin API in JavaScript. You write your extensions in TypeScript using the same visitor pattern that remark and rehype use. Satteri compiles to a native module for Node, to WASM for the browser, and ships as a single npm package called satteri. It is MIT licensed and the source is on GitHub at github.com/bruits/satteri.

You do not need to know Rust to use it. The entire plugin layer is JavaScript with full TypeScript types. The Rust crates are an implementation detail unless you want to extend the parser itself.

The Architecture: Rust Inside, JavaScript Outside

The Satteri monorepo contains seven Rust crates and one npm package. The Rust crates handle the parser (satteri-pulldown-cmark, a fork of pulldown-cmark with MDX support), the AST node types and codecs (satteri-ast), the MDX-to-JavaScript compiler (satteri-mdxjs-rs), an arena allocator for low-allocation AST construction (satteri-arena), the plugin trait for Rust plugins (satteri-plugin-api), and the NAPI bindings that bridge Rust and Node (satteri-napi-binding). The high-level satteri crate exposes a clean Rust API on top of all of that.

The npm package, also named satteri, wraps the NAPI bindings and adds the JavaScript-side plugin API. A typical conversion looks like this:

import { markdownToHtml, defineMdastPlugin } from "satteri";

const stripInlineCode = defineMdastPlugin({
  name: "strip-inline-code",
  inlineCode(node, ctx) {
    ctx.replaceNode(node, { type: "text", value: node.value });
  },
});

const { html } = markdownToHtml("Use `let` instead of `var`.", {
  mdastPlugins: [stripInlineCode],
});
// <p>Use let instead of var.</p>

The shape should look familiar: defineMdastPlugin returns a plugin object with a name and a visitor per node type, and the function markdownToHtml takes the plugin in an options bag. If you have written a remark or rehype plugin, you can read this code and recognize the pattern. That is the design goal.

Why Speed Matters for a Client-Side Editor

Browser-based Markdown engines are written in pure JavaScript. The most popular ones — marked, markdown-it, remark — are all single-threaded JavaScript parsers. They are fast enough for typical documents, but they hit a wall on long drafts. A 15,000-word technical article with 40 code blocks and 12 tables takes several seconds to parse in marked on a mid-range laptop. The same document in pulldown-cmark compiled to WASM parses in a fraction of a second.

For a static-site generator like Astro, where build performance compounds across thousands of documents, this is a real win. For a client-side editor that re-renders the document on every keystroke, it is transformative. The mental model changes from "throttle the keystroke handler" to "render on every input without thinking about it."

Satteri is positioned as the Markdown equivalent of what LightningCSS did for CSS and OXC did for JavaScript tooling: a native core with a JavaScript surface. If you have used LightningCSS to speed up a build pipeline, the architectural argument for Satteri will be familiar.

How Satteri Compares to Marked, remark, and pulldown-cmark-wasm

The Markdown parser landscape in JavaScript has three reasonable choices in 2026, plus Satteri.

marked is the lightweight default. About 30 KB minified, no dependencies, very fast for typical documents. The plugin model is limited — you can write tokenizers and renderer overrides, but the AST is shallow and there is no canonical MDAST. marked is what most simple client-side editors use under the hood.

remark + unified is the structured-pipeline option. The full unified ecosystem (remark, rehype, remark-rehype, rehype-stringify) gives you a deeply composable AST. It is also slow on large documents and the dependency graph is large. The unified ecosystem is the right choice when you need a deep transformation pipeline; it is the wrong choice when you need to render on every keystroke in the browser.

pulldown-cmark-wasm is the speed option. The CommonMark reference parser compiled to WebAssembly, with no plugin system and no AST exposed to JavaScript. You get bytes in, you get HTML out. Fast, but inflexible.

Satteri is the speed + flexibility option. Rust for the hot path, JavaScript for the plugins, full MDAST and HAST exposed to your code. The tradeoff is a larger bundle than marked (the WASM is several hundred kilobytes) and a smaller plugin ecosystem than unified. For a new client-side editor that needs to be fast and customizable, Satteri is now the most credible foundation.

The MDX Story: Components in Your Markdown

MDX is Markdown that lets you embed JSX components directly in the source. Satteri handles MDX via a fork of mdxjs-rs, which means it can compile an MDX document into executable JavaScript that imports your components. The whole pipeline runs in Rust; the MDX-to-JS output runs wherever you ship it.

For most md2rich-style tools, MDX is not relevant — the destination is a rich-text editor that does not render React. But for a long-form publishing tool that targets both a static site (where MDX makes sense) and a social platform (where the same source needs to become rich HTML), a single source format that compiles both ways is genuinely useful. Satteri is positioned to be that format.

The same MDX source can go through mdxToJs() for a React-based blog and markdownToHtml() for a paste-into-LinkedIn flow. The two paths share the same parser and the same plugin system, so a custom shortcode or callout works in both destinations without re-implementation.

Privacy by Construction: WASM, No Server

Satteri runs in two modes: a native module for Node, and WebAssembly for the browser. In the browser, the entire pipeline executes on the user's device. There is no server round-trip and no API call. The Satteri playground at satteri.bruits.org/playground is itself a working demonstration: type Markdown on the left, get rendered HTML on the right, watch the conversion happen in real time without any network activity after the page loads.

This is the same architectural pattern that md2rich uses. md2rich is a single static HTML page that converts your Markdown draft to the rich HTML that LinkedIn, X, and Medium expect on the clipboard. Nothing is uploaded; the conversion runs in your browser tab. If a future version of md2rich swapped its in-house JavaScript parser for a Satteri WASM build, the user experience would not change — your draft still never leaves the device — but the speed and the fidelity of complex constructs (nested tables, footnotes, MDX-style callouts) would both improve.

For any tool that touches unpublished drafts, this is the right architecture. The alternative — sending your draft to a server for conversion — means a copy of your unpublished work exists in someone else's log files. For a journalist, a lawyer, a researcher, or anyone who cares about source protection, that is a non-starter. Satteri is a private-by-construction pipeline because the WASM build makes the server round-trip unnecessary.

What This Means for md2rich and Other Paste-Into-Rich-Text Tools

The class of tools md2rich belongs to — client-side Markdown editors that produce rich text for social and long-form platforms — is exactly the class that benefits most from a faster Markdown engine. The bottleneck is no longer the UI; it is the parse. A 5 to 10x speedup on the parse step translates directly into a snappier editor and the ability to support longer documents without throttling the input.

If you are building a tool in this space in 2026, the Satteri architecture gives you four things you did not have before:

  • A fast core in Rust that you do not need to write yourself. The parser is pulldown-cmark with MDX extensions, battle-tested at the C and Rust level for over a decade.
  • A clean JavaScript plugin API that mirrors the remark / rehype pattern. The mental model you already have applies.
  • Full TypeScript types for every AST node and every plugin callback. No any escape hatches required.
  • A WASM build for the browser that runs without a server, on the user's device, on their data.

The main tradeoff is bundle size. The WASM build is several hundred kilobytes, which is fine for a tool that ships its own runtime (like md2rich or a desktop Markdown editor) and less fine for a tool that loads a Markdown engine as one of many dependencies. For paste-into-rich-text use cases, the size is a non-issue.

The 60-Second Workflow: From Satteri-Aware Markdown to LinkedIn

For a writer who drafts in Markdown and publishes to LinkedIn, X Articles, or Medium, Satteri changes nothing about the surface workflow and everything about the foundation underneath it. Here is the end-to-end flow as it stands in mid-2026:

  1. Draft in your favorite Markdown editor. Obsidian, iA Writer, VS Code, or a plain text file — the source format is the same.
  2. Copy the rendered rich HTML to your clipboard. With md2rich this is a single click: paste your Markdown source into the editor pane, click "Copy as Rich Text," and the rich HTML is on your clipboard.
  3. Paste into the destination. LinkedIn renders the formatting. X Articles does the same. Medium accepts the rich HTML and applies its own typography. Bluesky long-form handles it too.

What Satteri brings to this flow is the option for tools like md2rich to upgrade their underlying engine to a Rust core, which means faster rendering, more faithful constructs, and a foundation that can support MDX-style components for users who want them. The day-to-day experience for the writer does not change. The day-to-day experience for the developer of the tool changes a lot — and that is what makes the release worth paying attention to.

If you are a JavaScript developer who builds Markdown tooling, Satteri is the most interesting release of 2026 so far. The architecture is proven in adjacent problem spaces (LightningCSS, OXC), the maintainer has shipped the WASM build, and the plugin API is ergonomic enough to port existing remark plugins without a rewrite. For a client-side rich-text tool, it is the right foundation for the next generation.

To try the Satteri playground, visit satteri.bruits.org/playground. To convert your Markdown drafts to rich text for LinkedIn, X, and Medium, try md2rich — it is free, runs entirely in your browser, and never uploads your drafts.