A Rust project called Merman rebuilds Mermaid.js as a headless diagramming engine that never touches a browser or JavaScript runtime. The interesting part is not the speed, though it is fast. It is the decision to treat an existing tool's quirks as a specification worth matching exactly.
Most software that claims compatibility with something else is really claiming approximate resemblance. It works on the common cases, diverges quietly on the edges, and leaves users to discover the gaps through bug reports. Merman, a headless Rust reimplementation of Mermaid.js, takes the opposite position. It treats Mermaid not as inspiration but as a written specification, including the parts of Mermaid that are arguably mistakes, and it builds an enforcement apparatus to prove the match holds over time.
That stance is the most revealing thing about the project, more than its performance numbers or its long list of output formats. To understand why, it helps to look at what Merman actually does and the engineering posture that produced it.

What the project is
Mermaid.js turns plain text into diagrams. You write something like flowchart TD; A-->B; in a Markdown file or a documentation page, and Mermaid renders a flowchart. It has become the default way developers sketch architecture, sequence flows, and decision trees inside docs, because the diagrams live as text in version control rather than as opaque binary image files. The catch is that Mermaid is JavaScript, and rendering it traditionally means running a browser or a headless browser engine to produce the final image.
Merman removes that dependency entirely. It is a parsing, layout, and rendering stack written in Rust that targets [email protected] and never launches a browser or a JavaScript runtime. Feed it Mermaid text and it produces semantic JSON describing the diagram, layout JSON with computed geometry and edge routes, Mermaid-like SVG, raster formats including PNG, JPG, and PDF, and even ASCII or Unicode renderings suitable for terminals and log output. You can try it through the Merman Playground, which runs the engine compiled to WebAssembly.

The distribution is deliberately broad. There is a command-line tool installable with cargo install merman-cli, a Rust library crate with feature flags for SVG, ASCII, and raster output, a proc-macro that renders Mermaid fences inline in rustdoc, a browser and TypeScript package via wasm-bindgen, an experimental Typst plugin, and a stable C ABI through merman-ffi that reaches into C, C++, Swift, Kotlin, Dart, and Python. The same parsing and rendering core sits behind all of them.
Why headless matters more than it sounds
The practical argument for a browserless renderer is straightforward once you have tried to do this the hard way. Spinning up a headless Chromium instance to convert a diagram into a PNG inside a build pipeline or a server process is heavy, slow to start, and operationally awkward. It pulls a large external binary into your dependency tree, consumes hundreds of megabytes of memory, and introduces a process you have to manage and secure. For something as conceptually simple as drawing a flowchart from text, that is a lot of machinery.
Merman collapses all of it into a single native library or a static binary. A documentation build can render diagrams in-process. A Rust application can embed the renderer directly. A mobile app can link the FFI artifact and render diagrams without a webview. The performance follows from this architecture rather than from clever micro-optimization. On an Apple M4, the project's benchmark harness measured Merman using roughly 1.8 to 23 percent of Mermaid's JavaScript render time across a standard suite, somewhere between four and fifty-six times faster depending on the diagram, with a median around sixteen times. The maintainers are careful to add that speed is not a substitute for correctness, and that framing is the heart of the project.
The parity discipline
Here is where Merman departs from the usual reimplementation story. Anyone can write a Rust parser that handles flowcharts and call it Mermaid-compatible. The hard problem is the long tail of behavior: the exact way Mermaid lays out a dense compound graph, the precise geometry of an edge route, the surprising thing it does when you nest subgraphs three deep. Reimplementations usually punt on these and accept that they will look roughly right.
Merman builds an infrastructure specifically to refuse that compromise. Parsing and semantic output are locked against golden JSON snapshots stored as fixtures/**/*.golden.json. Layout geometry is locked separately in *.layout.golden.json files, which means a regression can be traced to a specific stage: parsing, geometry computation, or final SVG emission. Most demanding of all, the project keeps a corpus of more than 3,500 upstream SVG baselines across 23 diagram types, generated from the pinned official Mermaid rendering pipeline, and uses them as the end-to-end source of truth.
Those SVG comparisons do not demand byte-identical text, which would be brittle and meaningless. Instead the parity checks canonicalize the SVG DOM, normalize numeric geometry tokens to three decimal places, and compare the resulting structure. The stated goal is precise: not "it looks similar" but "it stays aligned," with any change that affects semantics, layout, or rendering caught and reviewed before it lands.

This required porting Mermaid's layout dependencies rather than substituting Rust-native equivalents. Merman includes dugong and dugong-graphlib, headless ports of the Dagre and Graphlib layout libraries that Mermaid uses for directed graphs, and manatee, a port of the Cytoscape and FCoSE compound-layout algorithms behind diagrams like architecture views and mindmaps. Reaching for a different layout algorithm would have been easier and would have produced perfectly reasonable diagrams. It would also have produced diagrams that differ from Mermaid's, which defeats the entire purpose.
The deeper claim about compatibility
There is a small philosophical statement buried in the parity policy, and it is worth pulling out. The maintainers write that when upstream Mermaid does something surprising, Merman matches and documents the behavior instead of replacing it with a cleaner Rust-specific interpretation. When an upstream sample cannot be rendered directly by the pinned Mermaid CLI, they keep the raw input as a parser-only fixture and create a documented normalized variant for layout and rendering parity.
That is a meaningful design ethic. It treats bug-for-bug compatibility as a feature, because the alternative, improving on the original where you think it errs, fragments the ecosystem. The value of a Mermaid diagram is that it renders the same way everywhere people expect Mermaid. A faster renderer that quietly draws things differently is not a Mermaid renderer at all, it is a fork wearing a familiar name. Merman's authors seem to understand that the contract they are honoring is not with the Mermaid source code but with the millions of diagrams already written against Mermaid's actual behavior.
This is the same discipline that makes a good programming-language reimplementation valuable. A second implementation of a language earns trust by passing the reference test suite, not by being elegant. Merman is doing for a diagramming tool what conformance suites do for languages and browsers, and it is doing so for a target that never published a formal specification in the first place. The 3,500 baseline corpus is, in effect, a specification reverse-engineered from the reference implementation's output.

Where it is honest about limits
The project does not oversell itself, which is its own kind of credibility signal. Mermaid leans heavily on SVG <foreignObject> elements to embed HTML labels, and those are poorly supported by rasterizers. Merman addresses this with a layered set of rendering entry points rather than pretending the problem away. There is render_svg_sync for strict Mermaid-parity output, render_svg_resvg_safe_sync for cases headed to a rasterizer or an SVG engine that handles <foreignObject> badly, and render_svg_readable_sync for inline previews that keep the original nodes but add fallback text overlays. The split acknowledges that "correct SVG" and "SVG that survives conversion to PNG" are genuinely different targets.
Raster export carries a default pixmap budget capping output at 8192 pixels per side, a guard against a diagram with a legitimately enormous viewBox triggering a huge memory allocation in a headless host. Callers who know what they are doing can opt into unbounded output. The compound layout for architecture diagrams is still being normalized against upstream Cytoscape geometry, and the documentation points to a living status file rather than claiming finished parity. The ASCII and Unicode text output ships deliberately bounded subsets for class, entity-relationship, and XY-chart diagrams, returning clear diagnostics on shapes it cannot yet render cleanly instead of producing garbled output.

The binary size disclosure is similarly candid. The FFI and WASM packages bundle the full parser, layout, and renderer, so they run roughly 9 to 17 megabytes per native library slice and about 9.8 megabytes uncompressed for the browser WASM artifact, dropping to 3.6 megabytes gzipped. The maintainers tell you to treat these as runtime dependencies rather than lightweight scripting shims, which is the honest framing for a tool that has absorbed an entire diagramming engine into a single artifact.
What to make of it
Merman is currently at version 0.8.0-alpha.1, dual-licensed under MIT and Apache-2.0, and explicitly unaffiliated with the Mermaid project. It is an independent compatibility implementation built by Mermaid users, and it carries the careful attribution notes that such a position demands, tracing its test fixtures back to upstream Mermaid documentation and tests.
The broader pattern it represents is worth watching. As more infrastructure gets rewritten in Rust for performance and deployment simplicity, the projects that matter will be the ones that take compatibility as seriously as Merman does, because a faster tool that breaks existing content trades one cost for another and usually loses. The interesting engineering here is not the renderer. It is the test corpus and the parity gates that turn a vague promise of compatibility into something a continuous-integration pipeline can verify on every commit. That apparatus, more than any benchmark, is what makes the claim believable.

Comments
Please log in or register to join the discussion