- Rust 82.8%
- Python 13.1%
- Mermaid 2.2%
- HTML 1.7%
- Shell 0.2%
| .github | ||
| benches | ||
| docs | ||
| scripts | ||
| src | ||
| tests | ||
| tmp | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| clippy.toml | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
mmdr
100–1400x faster Mermaid rendering. Pure Rust. Zero browser dependencies.
Performance
mmdr renders diagrams 100–1400x faster than mermaid-cli by eliminating browser overhead.
With the built-in font cache (warm after first run), tiny diagrams reach 500–900× (and --fastText exceeds 1600×).
| Diagram | mmdr | mermaid-cli | Speedup |
|---|---|---|---|
| Flowchart | 4.49 ms | 1,971 ms | 439x |
| Class Diagram | 4.67 ms | 1,907 ms | 408x |
| State Diagram | 3.97 ms | 1,968 ms | 496x |
| Sequence Diagram | 2.71 ms | 1,906 ms | 704x |
Tested on Intel Core Ultra 7 265V, Linux 6.18.7 | mermaid-cli 11.4.2 via Puppeteer/Chromium
Font cache (default, warm after first run)
Once the font cache is populated, tiny/common diagrams reach 500–900×:
| Diagram (tiny) | mmdr (warm cache) | mermaid-cli | Speedup |
|---|---|---|---|
| Flowchart | 2.96 ms | 2,259 ms | 764× |
| Class | 2.55 ms | 2,347 ms | 919× |
| State | 2.67 ms | 2,111 ms | 789× |
| Sequence | 3.75 ms | 2,010 ms | 536× |
Measured Feb 2, 2026 on the same machine.
Fast text metrics (optional, fastest)
Enable --fastText to use calibrated fallback widths for ASCII labels (avoids font DB load).
On tiny/common diagrams this reaches 1600–2069× speedups:
| Diagram (tiny) | mmdr --fastText |
mermaid-cli | Speedup |
|---|---|---|---|
| Flowchart | 1.32 ms | 2,116 ms | 1,601× |
| Class | 1.23 ms | 2,314 ms | 1,880× |
| State | 1.09 ms | 2,258 ms | 2,069× |
| Sequence | 1.16 ms | 2,158 ms | 1,868× |
Measured Feb 2, 2026 on the same machine.
Library Performance (no CLI overhead)
When used as a Rust library, mmdr is even faster with no process spawn overhead:
| Diagram | Library Time |
|---|---|
| Flowchart | 1.49 ms |
| Class Diagram | 2.51 ms |
| State Diagram | 2.04 ms |
| Sequence Diagram | 0.07 ms |
These are raw render times measured with Criterion, ideal for embedding in applications.
Extended Benchmarks
Performance on larger diagrams:
| Diagram | Nodes | mmdr | mermaid-cli | Speedup |
|---|---|---|---|---|
| flowchart (small) | 10 | 3.38 ms | 1,910 ms | 565x |
| flowchart (medium) | 50 | 8.71 ms | 2,018 ms | 232x |
| flowchart (large) | 200 | 47.00 ms | 2,276 ms | 48x |
The speedup advantage decreases for very large diagrams as actual layout computation becomes more significant relative to browser startup overhead. Still, mmdr remains 100x+ faster even for 200-node diagrams.
Why mmdr?
The official mermaid-cli spawns a headless Chromium browser for every diagram, adding 2-3 seconds of startup overhead.
| Use Case | mermaid-cli | mmdr |
|---|---|---|
| CI/CD pipeline with 50 diagrams | ~2 minutes | < 1 second |
| Real-time editor preview | Unusable lag | Instant |
| Batch doc generation | Coffee break | Blink of an eye |
mmdr parses Mermaid syntax natively in Rust and renders directly to SVG. No browser. No Node.js. No Puppeteer.
Installation
# From source
cargo install --path .
# Homebrew (macOS/Linux)
brew tap 1jehuang/mmdr && brew install mmdr
# Scoop (Windows)
scoop bucket add mmdr https://github.com/1jehuang/scoop-mmdr && scoop install mmdr
# AUR (Arch)
yay -S mmdr-bin
Quick Start
# Pipe diagram to stdout
echo 'flowchart LR; A-->B-->C' | mmdr -e svg
# File to file
mmdr -i diagram.mmd -o output.svg -e svg
mmdr -i diagram.mmd -o output.png -e png
# Render all diagrams from a Markdown file
mmdr -i README.md -o ./diagrams/ -e svg
Diagram Types
mmdr supports 23 Mermaid diagram types:
| Category | Diagrams |
|---|---|
| Core | Flowchart, Sequence, Class, State |
| Data | ER Diagram, Pie Chart, XY Chart, Quadrant Chart, Sankey |
| Planning | Gantt, Timeline, Journey, Kanban |
| Architecture | C4, Block, Architecture, Requirement |
| Other | Mindmap, Git Graph, ZenUML, Packet, Radar, Treemap |
|
Flowchart |
Class Diagram |
|
State Diagram |
Sequence Diagram |
Compare with mermaid-cli output
| Type | mmdr | mermaid-cli |
|---|---|---|
| Flowchart | ||
| Class | ||
| State | ||
| Sequence | ||
| ER Diagram | ||
| Pie Chart | ||
| Gantt | ||
| Mindmap | ||
| Timeline | ||
| Journey | ||
| Git Graph | ||
| XY Chart | ||
| Quadrant |
More Diagrams
Node Shapes
| Shape | Syntax |
|---|---|
| Rectangle | [text] |
| Round | (text) |
| Stadium | ([text]) |
| Diamond | {text} |
| Hexagon | {{text}} |
| Cylinder | [(text)] |
| Circle | ((text)) |
| Double Circle | (((text))) |
| Subroutine | [[text]] |
| Parallelogram | [/text/] |
| Trapezoid | [/text\] |
| Asymmetric | >text] |
Edge Styles
| Type | Syntax | Description |
|---|---|---|
| Arrow | --> |
Standard arrow |
| Open | --- |
No arrowhead |
| Dotted | -.-> |
Dashed line with arrow |
| Thick | ==> |
Bold arrow |
| Circle end | --o |
Circle decoration |
| Cross end | --x |
X decoration |
| Diamond end | <--> |
Bidirectional |
| With label | --|text|--> |
Labeled edge |
Subgraphs
flowchart TB
subgraph Frontend
A[React App] --> B[API Client]
end
subgraph Backend
C[Express Server] --> D[(PostgreSQL)]
end
B --> C
Subgraphs support:
- Custom labels
- Direction override (
direction LR) - Nesting
- Styling
Styling Directives
flowchart LR
A[Start] --> B[End]
classDef highlight fill:#f9f,stroke:#333
class A highlight
style B fill:#bbf,stroke:#333
linkStyle 0 stroke:red,stroke-width:2px
Supported:
classDef- Define CSS classesclass- Apply classes to nodes:::class- Inline class syntaxstyle- Direct node stylinglinkStyle- Edge styling%%{init}%%- Theme configuration
Features
Diagram types: flowchart / graph | sequenceDiagram | classDiagram | stateDiagram-v2 | erDiagram | pie | gantt | journey | timeline | mindmap | gitGraph | xychart-beta | quadrantChart | sankey-beta | kanban | C4Context | block-beta | architecture-beta | requirementDiagram | zenuml | packet-beta | radar-beta | treemap
Node shapes: rectangle, round-rect, stadium, circle, double-circle, diamond, hexagon, cylinder, subroutine, trapezoid, parallelogram, asymmetric
Edges: solid, dotted, thick | Decorations: arrow, circle, cross, diamond | Labels
Styling: classDef, class, :::class, style, linkStyle, %%{init}%%
Layout: subgraphs with direction, nested subgraphs, automatic spacing
Configuration
mmdr -i diagram.mmd -o out.svg -c config.json
mmdr -i diagram.mmd -o out.svg --nodeSpacing 60 --rankSpacing 120
config.json example
{
"themeVariables": {
"primaryColor": "#F8FAFF",
"primaryTextColor": "#1C2430",
"primaryBorderColor": "#C7D2E5",
"lineColor": "#7A8AA6",
"secondaryColor": "#F0F4FF",
"tertiaryColor": "#E8EEFF",
"edgeLabelBackground": "#FFFFFF",
"clusterBkg": "#F8FAFF",
"clusterBorder": "#C7D2E5",
"background": "#FFFFFF",
"fontFamily": "Inter, system-ui, sans-serif",
"fontSize": 13
},
"flowchart": {
"nodeSpacing": 50,
"rankSpacing": 50
}
}
How It Works
mmdr implements the entire Mermaid pipeline natively:
.mmd → parser.rs → ir.rs → layout.rs → render.rs → SVG → resvg → PNG
mermaid-cli requires browser infrastructure:
.mmd → mermaid-js → layout → Browser DOM → Puppeteer → Chromium → Screenshot → PNG
| mmdr | mermaid-cli | |
|---|---|---|
| Runtime | Native binary | Node.js + Chromium |
| Cold start | ~3 ms | ~2,000 ms |
| Memory | ~15 MB | ~300+ MB |
| Dependencies | None | Node.js, npm, Chromium |
Library Usage
Use mmdr as a Rust library in your project:
[dependencies]
mermaid-rs-renderer = { git = "https://github.com/1jehuang/mermaid-rs-renderer", tag = "v0.2.0" }
Minimal dependencies (for embedding)
For tools like Zola that only need SVG rendering, disable default features to avoid CLI and PNG dependencies:
[dependencies]
mermaid-rs-renderer = { git = "https://github.com/1jehuang/mermaid-rs-renderer", tag = "v0.2.0", default-features = false }
| Feature | Default | Description |
|---|---|---|
cli |
Yes | CLI binary and clap dependency |
png |
Yes | PNG output via resvg/usvg |
This reduces dependencies from ~180 to ~80 crates.
use mermaid_rs_renderer::{render, render_with_options, RenderOptions};
// Simple one-liner
let svg = render("flowchart LR; A-->B-->C").unwrap();
// With custom options
let opts = RenderOptions::modern()
.with_node_spacing(60.0)
.with_rank_spacing(80.0);
let svg = render_with_options("flowchart TD; X-->Y", opts).unwrap();
Full pipeline control
use mermaid_rs_renderer::{
parse_mermaid, compute_layout, render_svg,
Theme, LayoutConfig,
};
let diagram = "flowchart LR; A-->B-->C";
// Stage 1: Parse
let parsed = parse_mermaid(diagram).unwrap();
println!("Parsed {} nodes", parsed.graph.nodes.len());
// Stage 2: Layout
let theme = Theme::modern();
let config = LayoutConfig::default();
let layout = compute_layout(&parsed.graph, &theme, &config);
// Stage 3: Render
let svg = render_svg(&layout, &theme, &config);
With timing information
use mermaid_rs_renderer::{render_with_timing, RenderOptions};
let result = render_with_timing(
"flowchart LR; A-->B",
RenderOptions::default()
).unwrap();
println!("Rendered in {:.2}ms", result.total_ms());
println!(" Parse: {}us", result.parse_us);
println!(" Layout: {}us", result.layout_us);
println!(" Render: {}us", result.render_us);
Development
cargo test
cargo run -- -i docs/diagrams/architecture.mmd -o /tmp/out.svg -e svg
Remote build/test over SSH (optional):
export MMDR_REMOTE_HOST=<your-ssh-host-alias>
scripts/remote-cargo.sh test
scripts/remote-cargo.sh build --release
scripts/remote-cargo.sh bench --bench renderer
The wrapper uses rsync + ssh and keeps host/IP details in your local environment
or ~/.ssh/config, not in this repository.
Benchmarks:
cargo bench --bench renderer # Microbenchmarks
cargo build --release && python scripts/bench_compare.py # vs mermaid-cli
License
MIT