Mermaid.js: Generate Diagrams Directly from Code
Imagine sketching a flowchart, a sequence diagram, or a mind map without ever touching a mouse. With Mermaid.js you write plain‑text definitions right next to your source code, and the library turns them into crisp SVG diagrams on the fly. This approach keeps documentation in sync, reduces context‑switching, and makes version‑control diffs meaningful. In the next few minutes we’ll explore how to set up Mermaid, walk through three real‑world examples, and uncover a handful of pro tips that will make your diagrams feel native to your codebase.
What is Mermaid.js?
Mermaid.js is an open‑source JavaScript library that parses a lightweight markdown‑like syntax into SVG diagrams. It supports flowcharts, sequence diagrams, class diagrams, Gantt charts, state diagrams, and more. Because the definition lives in plain text, you can store it in .md files, embed it in Javadoc, or generate it programmatically from JSON.
Why use code‑first diagrams?
Traditional diagram tools lock you into a GUI, making updates painful and diffs unreadable. With Mermaid you get:
- Version‑control friendliness: each change is a line in a text file.
- Automation potential: generate diagrams from code or CI pipelines.
- Consistency: the same source can render in docs, wikis, or live dashboards.
Getting Started
The quickest way to try Mermaid is to drop the CDN script into any HTML page. The library automatically scans the document for pre elements with the class mermaid and replaces them with SVG output.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Mermaid Demo</title>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</head>
<body>
<pre class="mermaid">
graph TD
A[Start] --> B{Is it sunny?}
B -->|Yes| C[Go outside]
B -->|No| D[Stay indoors]
</pre>
</body>
</html>
Notice the mermaid.initialize({ startOnLoad: true }) call – it tells the library to process the page as soon as the DOM is ready. If you prefer a manual trigger, set startOnLoad to false and call mermaid.run() whenever you need.
Basic Syntax Overview
Mermaid’s syntax is intentionally terse. A diagram type is declared first, followed by a series of statements that describe nodes and edges. The most common types include:
graph– flowcharts (directed or undirected)sequenceDiagram– interaction timelinesclassDiagram– UML‑style class relationshipsstateDiagram– finite‑state machinesgantt– project timelines
Flowchart Example
Below is a minimal flowchart that models a simple login flow. The syntax uses arrows (-->) to indicate direction, and square brackets to create rounded nodes.
graph LR
A[Enter Username] --> B[Enter Password]
B --> C{Validate}
C -- Yes --> D[Dashboard]
C -- No --> E[Show Error]
E --> A
Pro tip: Use the %% comment syntax to annotate sections of a large diagram without affecting the rendering. This keeps complex charts readable for future contributors.
Practical Example 1: Visualizing an API Workflow
Many teams struggle to keep their API documentation up‑to‑date. By embedding a Mermaid diagram directly in a markdown file, you give readers a visual overview that evolves alongside the code.
graph TD
subgraph Client
C1[Web App] --> C2[REST Call]
end
subgraph Server
C2 --> S1[Auth Service]
S1 -->|Valid| S2[Business Logic]
S1 -->|Invalid| S3[401 Error]
S2 --> S4[Database Query]
S4 --> S5[Response Builder]
S5 --> C2
end
style Client fill:#f9f,stroke:#333,stroke-width:2px
style Server fill:#bbf,stroke:#333,stroke-width:2px
This diagram shows a client making a request, the server routing through authentication, handling errors, and finally hitting the database. Because the diagram lives in API_WORKFLOW.md, a pull request that modifies the authentication flow can also update the visual representation in the same commit.
Practical Example 2: State Machine for Order Processing
State diagrams excel at describing business processes that have distinct phases. Below is a state machine that tracks an e‑commerce order from creation to delivery, including cancellation paths.
stateDiagram-v2
[*] --> Created
Created --> Paid : payment_success
Created --> Cancelled : timeout
Paid --> Shipped : inventory_ok
Paid --> Cancelled : user_request
Shipped --> Delivered : carrier_confirm
Shipped --> Returned : customer_return
Returned --> Refunded : process_refund
Delivered --> [*]
Cancelled --> [*]
The stateDiagram-v2 keyword enables the newer syntax that supports history states and composite states. This diagram can be rendered in a Confluence page, a GitHub README, or even a Jupyter notebook, providing a single source of truth for the order lifecycle.
Advanced Features
Once you’re comfortable with the basics, Mermaid offers a suite of customization knobs that let you match corporate branding, improve accessibility, or generate diagrams dynamically.
Custom Themes
Mermaid ships with a few built‑in themes (default, forest, dark), but you can also define your own colors, fonts, and line styles via the themeVariables object.
mermaid.initialize({
startOnLoad: true,
theme: 'base',
themeVariables: {
primaryColor: '#0d47a1',
primaryTextColor: '#ffffff',
secondaryColor: '#90caf9',
lineColor: '#1976d2',
fontFamily: 'Helvetica, Arial, sans-serif'
}
});
Inject this script once on your site, and every diagram will inherit the palette, ensuring a consistent look across documentation, internal dashboards, and public tutorials.
Dynamic Diagrams with JavaScript
Sometimes the diagram content depends on runtime data—think of a CI pipeline that visualizes the current build graph. Mermaid’s render API returns an SVG string that you can insert into the DOM manually.
function renderPipelineGraph(pipeline) {
const definition = `
graph LR
${pipeline.stages.map(s => `${s.id}[${s.name}]`).join('\n')}
${pipeline.dependencies.map(d => `${d.from} --> ${d.to}`).join('\n')}
`;
mermaid.mermaidAPI.render('pipelineSvg', definition, (svg) => {
document.getElementById('pipelineContainer').innerHTML = svg;
});
}
// Example usage:
const pipeline = {
stages: [{id:'A', name:'Checkout'}, {id:'B', name:'Test'}, {id:'C', name:'Deploy'}],
dependencies: [{from:'A', to:'B'}, {from:'B', to:'C'}]
};
renderPipelineGraph(pipeline);
This pattern lets you feed live JSON from a backend, generate a fresh diagram on every page load, and still benefit from Mermaid’s rendering engine.
Pro tip: Cache the generated SVG in localStorage if the underlying data rarely changes. This reduces re‑render time and improves perceived performance on repeat visits.
Real‑World Use Cases
- Architecture Documentation – Teams embed service dependency graphs directly in their READMEs, keeping the visual map in sync with microservice registries.
- Education & Training – Instructors use sequence diagrams to illustrate algorithm steps, allowing students to edit the source and instantly see the effect.
- Project Management – Gantt charts generated from a JSON sprint backlog give stakeholders a live view of timelines without leaving the issue tracker.
- Compliance Audits – State diagrams can model data‑flow compliance (e.g., GDPR) and be exported as PDFs for audit packages.
Because Mermaid outputs SVG, the diagrams are resolution‑independent and printable at any size, making them suitable for both web and PDF exports.
Performance and Accessibility
Large diagrams can impact page load time. To mitigate this, load Mermaid lazily using the defer attribute or a dynamic import. For accessibility, add aria-label attributes to the container div that holds the SVG, describing the diagram’s purpose for screen readers.
<div id="orderStateDiagram" aria-label="State diagram of the order processing workflow"></div>
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: false });
const definition = `stateDiagram-v2 ...`;
mermaid.mermaidAPI.render('orderStateDiagram', definition, (svg) => {
document.getElementById('orderStateDiagram').innerHTML = svg;
});
</script>
By rendering the SVG only when the element enters the viewport (using IntersectionObserver), you keep initial paint fast while still delivering a rich visual experience.
Testing Mermaid Diagrams
When diagrams are part of a CI pipeline, you’ll want to verify they don’t break silently. One strategy is to snapshot‑test the generated SVG strings with a tool like Jest. If the SVG output changes unexpectedly, the test will fail, prompting a review.
test('order state diagram renders consistently', async () => {
const definition = `stateDiagram-v2
[*] --> Created
Created --> Paid
Paid --> Shipped
Shipped --> Delivered
Delivered --> [*]`;
const svg = await mermaid.render('testSvg', definition);
expect(svg).toMatchSnapshot();
});
Snapshots live alongside your source files, making it trivial to spot regressions caused by library upgrades or syntax changes.
Conclusion
Mermaid.js bridges the gap between code and visual communication, turning plain‑text definitions into professional diagrams that stay in lockstep with your source. By embedding Mermaid directly in documentation, CI pipelines, or interactive dashboards, you gain version‑controlled visuals, reduce maintenance overhead, and empower non‑technical stakeholders to grasp complex flows instantly. Whether you’re mapping API interactions, modeling state machines, or generating live pipeline graphs, the same simple syntax scales from a quick sketch to enterprise‑grade architecture diagrams. Start experimenting today—your future self will thank you for the clarity you built into the codebase.