1jehuang/mermaid-rs-renderer

A fast native Rust Mermaid diagram renderer. No browser required. 500-1000x faster than mermaid-cli.

1,704

stars

540

commits

Rust

primary language

Sep 7, 2026

updated

cli
diagram
flowchart
mermaid
rust
svg

README

mmdr

100–1400x faster Mermaid rendering. Pure Rust. Zero browser dependencies.

Installation | Quick Start | Benchmarks | Examples

Note: This library is under active early development. Visual output quality is improving rapidly but may not yet match mermaid-cli in all cases. Bug reports and PRs are welcome.

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×).

Performance comparison

Diagrammmdrmermaid-cliSpeedup
Flowchart4.49 ms1,971 ms439x
Class Diagram4.67 ms1,907 ms408x
State Diagram3.97 ms1,968 ms496x
Sequence Diagram2.71 ms1,906 ms704x

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-cliSpeedup
Flowchart2.96 ms2,259 ms764×
Class2.55 ms2,347 ms919×
State2.67 ms2,111 ms789×
Sequence3.75 ms2,010 ms536×

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 --fastTextmermaid-cliSpeedup
Flowchart1.32 ms2,116 ms1,601×
Class1.23 ms2,314 ms1,880×
State1.09 ms2,258 ms2,069×
Sequence1.16 ms2,158 ms1,868×

Measured Feb 2, 2026 on the same machine.

Pipeline breakdown

Library Performance (no CLI overhead)

When used as a Rust library, mmdr is even faster with no process spawn overhead:

Library performance

DiagramLibrary Time
Flowchart1.49 ms
Class Diagram2.51 ms
State Diagram2.04 ms
Sequence Diagram0.07 ms

These are raw render times measured with Criterion, ideal for embedding in applications.

Extended Benchmarks

Performance on larger diagrams:

DiagramNodesmmdrmermaid-cliSpeedup
flowchart (small)103.38 ms1,910 ms565x
flowchart (medium)508.71 ms2,018 ms232x
flowchart (large)20047.00 ms2,276 ms48x

The speedup advantage decreases for very large diagrams as actual layout computation becomes more significant relative to browser startup overhead. The 200-node case above is still 48x faster in this measurement.

Why mmdr?

The official mermaid-cli spawns a headless Chromium browser for every diagram, adding 2-3 seconds of startup overhead.

Use Casemermaid-climmdr
CI/CD pipeline with 50 diagrams~2 minutes< 1 second
Real-time editor previewUnusable lagInstant
Batch doc generationCoffee breakBlink of an eye

mmdr parses Mermaid syntax natively in Rust and renders directly to SVG. No browser. No Node.js. No Puppeteer.

Installation

# crates.io (recommended)
cargo install mermaid-rs-renderer

# 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

# Nix (flake)
nix run github:1jehuang/mermaid-rs-renderer -- --help
nix profile install github:1jehuang/mermaid-rs-renderer

Quick Start

# Pipe diagram to stdout
echo 'flowchart LR; A-->B-->C' | mmdr -e svg

# Read from stdin, write to a file (use '-i -' for explicit stdin)
echo 'flowchart LR; A-->B-->C' | mmdr -i - -o out.svg -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

By default the output uses the diagram's natural dimensions (the root SVG width/height match the viewBox, so there is no letterbox padding). Pass --width/--height to force explicit output dimensions.

Diagram Types

mmdr supports 23 Mermaid diagram types:

CategoryDiagrams
CoreFlowchart, Sequence, Class, State
DataER Diagram, Pie Chart, XY Chart, Quadrant Chart, Sankey
PlanningGantt, Timeline, Journey, Kanban
ArchitectureC4, Block, Architecture, Requirement
OtherMindmap, Git Graph, ZenUML, Packet, Radar, Treemap
Flowchart
Flowchart
Class Diagram
Class Diagram
State Diagram
State Diagram
Sequence Diagram
Sequence Diagram
Compare with mermaid-cli output
Typemmdrmermaid-cli
Flowchart
Class
State
Sequence
ER Diagram
Pie Chart
Gantt
Mindmap
Timeline
Journey
Git Graph
XY Chart
Quadrant

More Diagrams

Node Shapes
ShapeSyntax
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
TypeSyntaxDescription
Arrow-->Standard arrow
Open---No arrowhead
Dotted-.->Dashed line with arrow
Thick==>Bold arrow
Circle end--oCircle decoration
Cross end--xX 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 classes
  • class - Apply classes to nodes
  • :::class - Inline class syntax
  • style - Direct node styling
  • linkStyle - 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
mmdr -i diagram.mmd -o out.svg --preferredAspectRatio 16:9

preferredAspectRatio is layout-aware for graph diagrams: the renderer first rebalances geometry toward the target ratio, then fits final SVG dimensions to that ratio.

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
  },
  "preferredAspectRatio": "16:9",
  "flowchart": {
    "nodeSpacing": 50,
    "rankSpacing": 50
  }
}

How It Works

Architecture comparison

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
mmdrmermaid-cli
RuntimeNative binaryNode.js + Chromium
Cold start~3 ms~2,000 ms
Memory~15 MB~300+ MB
DependenciesNoneNode.js, npm, Chromium

Library Usage

Use mmdr as a Rust library in your project:

[dependencies]
mermaid-rs-renderer = "0.3.1"
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 = { version = "0.3.1", default-features = false }
FeatureDefaultDescription
cliYesCLI binary and clap dependency
pngYesPNG output via resvg/usvg

With current locked dependencies, this reduces the dependency graph from about 123 crates to about 71 crates.

For unreleased commits only:

[dependencies]
mermaid-rs-renderer = { git = "https://github.com/1jehuang/mermaid-rs-renderer", rev = "<commit-sha>" }
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 target/out.svg -e svg

Remote build/test over SSH (optional):

scripts/remote-cargo.sh test
scripts/remote-cargo.sh build --release
scripts/remote-cargo.sh bench --bench renderer

# Optional override
MMDR_REMOTE_HOST=my-builder scripts/remote-cargo.sh test

The wrapper uses rsync + ssh and keeps host/IP details in your local environment or ~/.ssh/config, not in this repository. By default it syncs into an isolated directory under remote ~/.cache with rsync --delete, so it will not touch your normal remote working copy unless you set MMDR_REMOTE_DIR to that path.

Benchmarks:

cargo bench --features benchmark --bench renderer  # Microbenchmarks
cargo build --locked --release && python3 scripts/bench_compare.py  # full suite vs mermaid-cli
python3 scripts/bench_render.py --help  # focused end-to-end PNG benchmark options

For a faster optimized development build, use cargo build --profile release-fast. The regular release profile keeps fat LTO for published binaries.

Release process: see docs/release.md.

License

MIT

Contributors

1jehuang

500 commits

fondoger

17 commits

dependabot[bot]

15 commits

smitbarmase

5 commits

1jehuang/mermaid-rs-renderer

A fast native Rust Mermaid diagram renderer. No browser required. 500-1000x faster than mermaid-cli.

1,704

stars

540

commits

Rust

primary language

Sep 7, 2026

updated

cli
diagram
flowchart
mermaid
rust
svg

README

mmdr

100–1400x faster Mermaid rendering. Pure Rust. Zero browser dependencies.

Installation | Quick Start | Benchmarks | Examples

Note: This library is under active early development. Visual output quality is improving rapidly but may not yet match mermaid-cli in all cases. Bug reports and PRs are welcome.

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×).

Performance comparison

Diagrammmdrmermaid-cliSpeedup
Flowchart4.49 ms1,971 ms439x
Class Diagram4.67 ms1,907 ms408x
State Diagram3.97 ms1,968 ms496x
Sequence Diagram2.71 ms1,906 ms704x

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-cliSpeedup
Flowchart2.96 ms2,259 ms764×
Class2.55 ms2,347 ms919×
State2.67 ms2,111 ms789×
Sequence3.75 ms2,010 ms536×

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 --fastTextmermaid-cliSpeedup
Flowchart1.32 ms2,116 ms1,601×
Class1.23 ms2,314 ms1,880×
State1.09 ms2,258 ms2,069×
Sequence1.16 ms2,158 ms1,868×

Measured Feb 2, 2026 on the same machine.

Pipeline breakdown

Library Performance (no CLI overhead)

When used as a Rust library, mmdr is even faster with no process spawn overhead:

Library performance

DiagramLibrary Time
Flowchart1.49 ms
Class Diagram2.51 ms
State Diagram2.04 ms
Sequence Diagram0.07 ms

These are raw render times measured with Criterion, ideal for embedding in applications.

Extended Benchmarks

Performance on larger diagrams:

DiagramNodesmmdrmermaid-cliSpeedup
flowchart (small)103.38 ms1,910 ms565x
flowchart (medium)508.71 ms2,018 ms232x
flowchart (large)20047.00 ms2,276 ms48x

The speedup advantage decreases for very large diagrams as actual layout computation becomes more significant relative to browser startup overhead. The 200-node case above is still 48x faster in this measurement.

Why mmdr?

The official mermaid-cli spawns a headless Chromium browser for every diagram, adding 2-3 seconds of startup overhead.

Use Casemermaid-climmdr
CI/CD pipeline with 50 diagrams~2 minutes< 1 second
Real-time editor previewUnusable lagInstant
Batch doc generationCoffee breakBlink of an eye

mmdr parses Mermaid syntax natively in Rust and renders directly to SVG. No browser. No Node.js. No Puppeteer.

Installation

# crates.io (recommended)
cargo install mermaid-rs-renderer

# 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

# Nix (flake)
nix run github:1jehuang/mermaid-rs-renderer -- --help
nix profile install github:1jehuang/mermaid-rs-renderer

Quick Start

# Pipe diagram to stdout
echo 'flowchart LR; A-->B-->C' | mmdr -e svg

# Read from stdin, write to a file (use '-i -' for explicit stdin)
echo 'flowchart LR; A-->B-->C' | mmdr -i - -o out.svg -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

By default the output uses the diagram's natural dimensions (the root SVG width/height match the viewBox, so there is no letterbox padding). Pass --width/--height to force explicit output dimensions.

Diagram Types

mmdr supports 23 Mermaid diagram types:

CategoryDiagrams
CoreFlowchart, Sequence, Class, State
DataER Diagram, Pie Chart, XY Chart, Quadrant Chart, Sankey
PlanningGantt, Timeline, Journey, Kanban
ArchitectureC4, Block, Architecture, Requirement
OtherMindmap, Git Graph, ZenUML, Packet, Radar, Treemap
Flowchart
Flowchart
Class Diagram
Class Diagram
State Diagram
State Diagram
Sequence Diagram
Sequence Diagram
Compare with mermaid-cli output
Typemmdrmermaid-cli
Flowchart
Class
State
Sequence
ER Diagram
Pie Chart
Gantt
Mindmap
Timeline
Journey
Git Graph
XY Chart
Quadrant

More Diagrams

Node Shapes
ShapeSyntax
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
TypeSyntaxDescription
Arrow-->Standard arrow
Open---No arrowhead
Dotted-.->Dashed line with arrow
Thick==>Bold arrow
Circle end--oCircle decoration
Cross end--xX 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 classes
  • class - Apply classes to nodes
  • :::class - Inline class syntax
  • style - Direct node styling
  • linkStyle - 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
mmdr -i diagram.mmd -o out.svg --preferredAspectRatio 16:9

preferredAspectRatio is layout-aware for graph diagrams: the renderer first rebalances geometry toward the target ratio, then fits final SVG dimensions to that ratio.

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
  },
  "preferredAspectRatio": "16:9",
  "flowchart": {
    "nodeSpacing": 50,
    "rankSpacing": 50
  }
}

How It Works

Architecture comparison

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
mmdrmermaid-cli
RuntimeNative binaryNode.js + Chromium
Cold start~3 ms~2,000 ms
Memory~15 MB~300+ MB
DependenciesNoneNode.js, npm, Chromium

Library Usage

Use mmdr as a Rust library in your project:

[dependencies]
mermaid-rs-renderer = "0.3.1"
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 = { version = "0.3.1", default-features = false }
FeatureDefaultDescription
cliYesCLI binary and clap dependency
pngYesPNG output via resvg/usvg

With current locked dependencies, this reduces the dependency graph from about 123 crates to about 71 crates.

For unreleased commits only:

[dependencies]
mermaid-rs-renderer = { git = "https://github.com/1jehuang/mermaid-rs-renderer", rev = "<commit-sha>" }
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 target/out.svg -e svg

Remote build/test over SSH (optional):

scripts/remote-cargo.sh test
scripts/remote-cargo.sh build --release
scripts/remote-cargo.sh bench --bench renderer

# Optional override
MMDR_REMOTE_HOST=my-builder scripts/remote-cargo.sh test

The wrapper uses rsync + ssh and keeps host/IP details in your local environment or ~/.ssh/config, not in this repository. By default it syncs into an isolated directory under remote ~/.cache with rsync --delete, so it will not touch your normal remote working copy unless you set MMDR_REMOTE_DIR to that path.

Benchmarks:

cargo bench --features benchmark --bench renderer  # Microbenchmarks
cargo build --locked --release && python3 scripts/bench_compare.py  # full suite vs mermaid-cli
python3 scripts/bench_render.py --help  # focused end-to-end PNG benchmark options

For a faster optimized development build, use cargo build --profile release-fast. The regular release profile keeps fat LTO for published binaries.

Release process: see docs/release.md.

License

MIT

Contributors

1jehuang

500 commits

fondoger

17 commits

dependabot[bot]

15 commits

smitbarmase

5 commits

Languages

Rust

84.5%

Python

13.8%

Mermaid

1.5%