StreamMDX is a streaming-first Markdown/MDX renderer for React with a worker-first pipeline, incremental patch application, deterministic snapshot compilation, and reliability tooling for people who care about correctness under load.
Primary links: Website Β· Docs Β· Demo Β· Showcase Β· Benchmarks Β· Perf Harness Β· npm
Tip
If you want the default app integration, install stream-mdx, host the bundled worker as a static asset, and start with <StreamingMarkdown />.1
- Why This Exists
- At a Glance
- Install Profiles
- Quickstart
- Usage Patterns
- Package Matrix
- Feature Surface
- Repository Layout
- Common Workflows
- Architecture Summary
- Documentation Map
- Reliability, Determinism, and Performance
- Security and Deployment Notes
- Contributing
- License
Most Markdown renderers are optimized for static strings. StreamMDX is built for the harder case:
- append-only streams from LLMs, agents, logs, or structured event sources
- React applications that need to stay responsive while content is still arriving
- deployments that want worker isolation, hosted assets, and explicit CSP/security boundaries
- teams that want regression fixtures, seeded replay, snapshot parity, and measurable performance instead of hand-wavy claims
The repo is intentionally split so you can consume it at different levels:
stream-mdxif you want the batteries-included app-facing dependency@stream-mdx/reactif you want the renderer directly@stream-mdx/workerand@stream-mdx/coreif you need the worker/runtime pieces separately@stream-mdx/plugins/*,@stream-mdx/protocol, and@stream-mdx/tuiif you are extending the pipeline or consuming the patch stream outside React
| Surface | What it is for | Where to start |
|---|---|---|
stream-mdx |
Recommended install for React apps | packages/stream-mdx/README.md |
| Docs site | Public docs, guides, showcase, benchmark pages | https://stream-mdx.vercel.app/docs |
| Live demo | Interactive streaming renderer sandbox | https://stream-mdx.vercel.app/demo |
| Benchmarks | In-browser comparison and timing views | https://stream-mdx.vercel.app/benchmarks |
| Perf harness | Focused perf surface and reproducible runs | https://stream-mdx.vercel.app/perf/harness |
| Example app | Minimal Next.js starter | examples/streaming-markdown-starter |
| Docs source | Markdown docs consumed by the docs app | docs/ |
| Profile | Install command | Use when |
|---|---|---|
| Convenience | npm install stream-mdx |
You want stable app-facing imports and the default React surface. |
| Modular | npm install @stream-mdx/react @stream-mdx/worker @stream-mdx/core @stream-mdx/plugins |
You want to own the wiring explicitly or publish a library on top. |
| Mermaid addon | npm install @stream-mdx/mermaid |
You want fenced mermaid blocks rendered as diagrams. |
| Tailwind theme | npm install @stream-mdx/theme-tailwind |
You want an optional CSS baseline for streaming markdown output. |
| TUI / protocol | npm install @stream-mdx/protocol @stream-mdx/tui |
You are consuming patch streams outside the browser. |
Recommended baseline:
npm install stream-mdxMinimal modular baseline:
npm install @stream-mdx/react @stream-mdx/worker @stream-mdx/core @stream-mdx/pluginsmkdir -p public/workers
cp node_modules/@stream-mdx/worker/dist/hosted/markdown-worker.js public/workers/markdown-worker.js"use client";
import { StreamingMarkdown } from "stream-mdx";
export function Demo({ text }: { text: string }) {
return (
<StreamingMarkdown
text={text}
worker="/workers/markdown-worker.js"
features={{
tables: true,
html: true,
math: true,
mdx: true,
footnotes: true,
codeHighlighting: "incremental",
}}
mdxCompileMode="worker"
prewarmLangs={["tsx", "bash", "json"]}
/>
);
}npm install
npm run build:packages
npm run docs:worker:build:raw
npm run docs:snapshots:build:raw
npm -w stream-mdx-docs run devNote
StreamingMarkdown is a client component. In Next.js App Router, import it behind a "use client" boundary.
"use client";
import { StreamingMarkdown } from "stream-mdx";
export function Article({ markdown }: { markdown: string }) {
return (
<StreamingMarkdown
text={markdown}
worker="/workers/markdown-worker.js"
features={{ tables: true, html: true, math: true, mdx: true }}
caret="block"
/>
);
}"use client";
import { useEffect, useRef } from "react";
import { StreamingMarkdown, type StreamingMarkdownHandle } from "stream-mdx";
export function LiveStream({ chunks }: { chunks: string[] }) {
const ref = useRef<StreamingMarkdownHandle>(null);
useEffect(() => {
let cancelled = false;
async function run() {
ref.current?.restart();
for (const chunk of chunks) {
if (cancelled) break;
ref.current?.append(chunk);
ref.current?.flushPending();
await ref.current?.waitForIdle();
}
ref.current?.finalize();
}
void run();
return () => {
cancelled = true;
};
}, [chunks]);
return <StreamingMarkdown ref={ref} managedWorker worker="/workers/markdown-worker.js" />;
}import { ComponentRegistry, MarkdownBlocksRenderer } from "@stream-mdx/react/server";
import { compileMarkdownSnapshot } from "stream-mdx/worker/node";
export default async function Page() {
const { blocks } = await compileMarkdownSnapshot({
text: "# Server render\n\nThis page was compiled ahead of time.",
init: {
docPlugins: {
tables: true,
html: true,
mdx: true,
math: true,
footnotes: true,
},
mdx: { compileMode: "server" },
prewarmLangs: ["typescript"],
},
});
return <MarkdownBlocksRenderer blocks={blocks} componentRegistry={new ComponentRegistry()} />;
}import { MermaidBlock } from "@stream-mdx/mermaid";
import { StreamingMarkdown } from "stream-mdx";
export function DiagramDoc({ text }: { text: string }) {
return <StreamingMarkdown text={text} worker="/workers/markdown-worker.js" components={{ mermaid: MermaidBlock }} />;
}import { createDocumentPluginPreset } from "@stream-mdx/plugins/document";
import { createTablesPlugin } from "@stream-mdx/plugins/tables";
import { createMathPlugin } from "@stream-mdx/plugins/math";If you are deciding between package layers:
- Use
stream-mdxunless you have a concrete reason not to. - Drop to
@stream-mdx/*when you need tighter control over bundling, entry points, or internal wiring. - Reach for
@stream-mdx/protocolor@stream-mdx/tuionly when you are intentionally consuming the patch/event model outside React.
| Package | Role | Notes |
|---|---|---|
stream-mdx |
Convenience wrapper | Re-exports the main React API and common subpaths. |
@stream-mdx/react |
React renderer | <StreamingMarkdown />, renderer store, scheduler, server render helpers, sticky-scroll components. |
@stream-mdx/worker |
Worker runtime | Worker client utilities, Node helpers, hosted worker bundle, direct compile helpers. |
@stream-mdx/core |
Core contracts | Types, snapshots, sanitization primitives, perf helpers, patch batching/coalescing helpers. |
@stream-mdx/plugins |
Built-in plugin suite | Tables, HTML, math, MDX, footnotes, callouts, registry helpers. |
@stream-mdx/mermaid |
Optional addon | Diagram rendering for fenced mermaid blocks. |
@stream-mdx/protocol |
External protocol surface | JSON/object protocol types for patch/event transport. |
@stream-mdx/tui |
Terminal helpers | NDJSON parsing and snapshot-store helpers for TUI consumers. |
@stream-mdx/theme-tailwind |
Optional theme CSS | Tailwind-friendly styling baseline for markdown output. |
apps/docs |
Product/docs site | The live docs, showcase, demo, and benchmark surfaces. |
examples/streaming-markdown-starter |
Minimal example app | Lightweight starter for local integration and manual QA. |
| Capability | Browser streaming | Node snapshot compile | Notes |
|---|---|---|---|
| Core Markdown + GFM blocks | π’ | π’ | Worker-first parsing and stable block snapshots. |
| Tables | π’ | π’ | Table-specific rendering hooks and tracked regressions. |
| Footnotes | π’ | π’ | Footnote aggregation with style regression coverage. |
| Sanitized HTML | π’ | π’ | Prefer trusted content and explicit allowlists. |
| Math | π’ | π’ | Inline + display math with KaTeX-compatible rendering paths. |
| MDX blocks | π’ | π’ | worker and server compile modes are both supported. |
| Incremental Shiki highlighting | π’ | n/a | final, incremental, and live code highlighting modes. |
| Mermaid addon | π’ | π’ | Provided via @stream-mdx/mermaid. |
| Custom plugins / regex extensions | π’ | π’ | Build on @stream-mdx/plugins and the worker pipeline. |
| TUI / NDJSON consumption | n/a | π’ | Use @stream-mdx/protocol and @stream-mdx/tui. |
| Seeded replay + snapshot regression harness | π’ | π’ | HTML/style snapshots, seeded smoke, determinism tooling. |
stream-mdx/
βββ apps/
β βββ docs/ Next.js docs, demo, showcase, and benchmark site
βββ docs/ Deep reference docs, manuals, checklists, and plans
βββ examples/
β βββ streaming-markdown-starter/ Minimal starter app
βββ packages/
β βββ markdown-v2-core/ Types, snapshots, sanitization, perf helpers
β βββ markdown-v2-mermaid/ Mermaid addon
β βββ markdown-v2-plugins/ Built-in plugin suite
β βββ markdown-v2-protocol/ JSON/object protocol contracts
β βββ markdown-v2-react/ React renderer, scheduler, server helpers
β βββ markdown-v2-tui/ TUI and NDJSON helpers
β βββ markdown-v2-worker/ Worker client, hosted worker, Node helpers
β βββ stream-mdx/ Convenience wrapper package
β βββ theme-tailwind/ Optional theme styles
βββ scripts/
β βββ determinism/ Determinism and parity tooling
β βββ perf/ Perf harness, compare, and gate scripts
β βββ regression/ HTML/style regression runners
βββ tests/
β βββ determinism/ Determinism fixtures
β βββ regression/ Regression fixtures and snapshots
βββ CONTRIBUTING.md
βββ DEPLOYMENT.md
βββ SECURITY.md
βββ package.json
| Goal | Command | Notes |
|---|---|---|
| Install workspace deps | npm install |
Requires Node >=20. |
| Build packages | npm run build:packages |
Builds all publishable packages. |
| Build everything | npm run build |
Includes the starter app build. |
| Run all workspace tests | npm test |
Package-level tests across the monorepo. |
| Build hosted worker for docs/app surfaces | npm run docs:worker:build |
Produces and copies markdown-worker.js. |
| Build docs snapshots | npm run docs:snapshots:build |
Compiles markdown docs into snapshot artifacts. |
| Run docs locally | npm run docs:dev |
Prepares packages, worker, docs snapshots, then starts Next dev. |
| Build docs for production | npm run docs:build |
End-to-end docs build/export path. |
| Run regression suites | npm run test:regression |
HTML + style snapshot suites. |
| Run seeded replay smoke | npm run test:regression:seeded-smoke:server |
Managed-server seeded regression smoke. |
| Run reliability package checks | npm run test:reliability:packages |
Focused package-level reliability checks. |
| Run docs reliability checks | npm run test:reliability:docs |
Style snapshots + runtime race checks. |
| Run determinism matrix | npm run determinism:matrix |
Worker determinism surface. |
| Run perf harness | npm run perf:harness |
Baseline perf capture. |
| Compare perf runs | npm run perf:compare |
Candidate vs base analysis. |
| Release gates | npm run release:gates |
Current pre-release gate set. |
A useful local loop for maintainers is:
npm install
npm run build:packages
npm run test:regression:seeded-smoke:server
npm run docs:dev- Worker-first parsing
- Markdown/MDX parsing and heavy enrichment happen off the main thread.
- The worker emits patch batches rather than a full-tree rerender on each update.
- Renderer store + patch scheduler
- The React layer owns a node/block store, applies patches incrementally, and schedules work under frame budgets.
- Semantic vs enrichment work is tracked explicitly in the current reliability hardening path.
- Snapshot compilation path
- The same ecosystem can compile Markdown into block snapshots for SSR, SSG, and static export flows.
- The docs site uses this model during build.
- Reliability and replay tooling
- Regression fixtures, seeded replay, style snapshots, runtime race tests, and release gates exist in-repo.
- This is a library project with a testing surface, not just a render component.
| If you are... | Read this first | Then |
|---|---|---|
| Integrating into a React app | docs/GETTING_STARTED.md |
docs/PUBLIC_API.md, docs/REACT_INTEGRATION_GUIDE.md |
| Extending the worker/plugin stack | docs/STREAMING_MARKDOWN_PLUGINS_COOKBOOK.md |
docs/PLUGIN_ABI.md, docs/STREAMING_MARKDOWN_V2_STATUS.md |
| Evaluating correctness/reliability | docs/REGRESSION_TESTING.md |
docs/STREAMING_CORRECTNESS_CONTRACT.md, docs/STREAMING_CORRECTNESS_EXECUTION_PLAN.md |
| Evaluating performance | docs/PERF_HARNESS.md |
docs/PERFORMANCE_GUIDE.md, docs/PERF_QUALITY_CHANGELOG.md |
| Using non-browser / TUI surfaces | docs/TUI_GUIDE.md |
docs/TUI_MINIMAL_EXAMPLE.md, examples/tui-minimal/README.md, docs/CLI_USAGE.md, docs/STREAMMDX_JSON_DIFF_SPEC.md |
| Topic | Repo doc | Site route |
|---|---|---|
| Docs overview | docs/README.md |
https://stream-mdx.vercel.app/docs |
| Getting started | docs/GETTING_STARTED.md |
https://stream-mdx.vercel.app/docs/getting-started |
| Public API | docs/PUBLIC_API.md |
https://stream-mdx.vercel.app/docs/public-api |
| React integration | docs/REACT_INTEGRATION_GUIDE.md |
https://stream-mdx.vercel.app/docs/react-integration |
| Plugin cookbook | docs/STREAMING_MARKDOWN_PLUGINS_COOKBOOK.md |
https://stream-mdx.vercel.app/docs/plugins-cookbook |
| Status / architecture | docs/STREAMING_MARKDOWN_V2_STATUS.md |
https://stream-mdx.vercel.app/docs/status |
| Streamdown comparison | docs/STREAMDOWN_COMPARISON.md |
https://stream-mdx.vercel.app/docs/streamdown-comparison |
| Minimal TUI example | docs/TUI_MINIMAL_EXAMPLE.md |
examples/tui-minimal/README.md |
| Showcase index | apps/docs/content/showcase/index.ts |
https://stream-mdx.vercel.app/showcase |
| Guides index | apps/docs/content/guides/index.ts |
https://stream-mdx.vercel.app/guides |
This repo is unusually heavy on verification because streaming renderers fail in ways that are easy to miss if you only test final static output.
| Concern | Current mechanism | Entry point |
|---|---|---|
| HTML regression parity | Seeded browser snapshot runner | npm run test:regression:html |
| CSS/style parity | Computed-style snapshots | npm run test:regression:styles |
| Seeded smoke | Managed-server replay on selected fixtures | npm run test:regression:seeded-smoke:server |
| Runtime races | Worker/runtime race checks | npm run test:runtime:worker-races |
| Determinism | Worker matrix + HTML parity tools | npm run determinism:matrix, npm run determinism:html-parity |
| Perf baselines | Harness capture and comparisons | npm run perf:harness, npm run perf:compare, npm run perf:gate |
| Release gating | Aggregated release checks | npm run release:gates |
Useful references:
docs/REGRESSION_TESTING.mddocs/BASELINE_UPDATE_POLICY.mddocs/DETERMINISM.mddocs/PERF_HARNESS.mddocs/PERF_QUALITY_CHANGELOG.mddocs/STREAMING_CORRECTNESS_CONTRACT.mddocs/STREAMING_MARKDOWN_RELEASE_CHECKLIST.md
- Hosted workers are the recommended production path; they keep the worker URL explicit and fit stricter CSPs better than
blob:fallbacks.1 - HTML rendering is a security boundary. Treat custom allowlists and overrides as security-sensitive configuration, not as mere presentation choices.
- MDX has two compile modes:
workerfor self-contained browser compilationserverwhen you want an explicit app-owned compile endpoint and tighter control over the compile boundary
- The repo includes both a Vercel-hosted site and a GitHub Pages mirror.2
| Resource | Link |
|---|---|
| Contributing guide | CONTRIBUTING.md |
| Security policy | SECURITY.md |
| Deployment notes | DEPLOYMENT.md |
| Code of conduct | CODE_OF_CONDUCT.md |
| Docs navigator | docs/README.md |
If you are contributing in the renderer/worker core, the minimum useful context is usually:
docs/PUBLIC_API.mddocs/STREAMING_MARKDOWN_V2_STATUS.mddocs/STREAMING_CORRECTNESS_CONTRACT.mddocs/STREAMING_CORRECTNESS_EXECUTION_PLAN.md
StreamMDX is released under the MIT License.
Footnotes
-
Hosting
markdown-worker.jsfrom your own static assets avoids the need for ablob:worker policy in stricter CSP setups. β© β©2 -
The Vercel deployment is the current primary site. GitHub Pages remains available as a mirror at https://kmccleary3301.github.io/stream-mdx/. β©