All articles

Mermaid Diagrams from Real Code: The 5-Minute Setup Guide

Stop hand-drawing architecture diagrams that rot the moment your code changes. Here's how to render Mermaid diagrams straight from your source in under five minutes.

D

DocPilot Team

AI documentation research and engineering from Onzira Labs.

6 min read

Why your diagrams are already out of date

Open your repository's architecture diagram. Now look at the src/ folder. If you're like most teams, those two views stopped agreeing weeks ago. Someone added a service, a route moved, a dependency got deprecated, and the pretty boxes-and-arrows in your wiki are now fiction.

The fix isn't discipline. It's automation. Mermaid is a JavaScript-based diagramming tool that renders from text, and GitHub, GitLab, and most static-site generators render it natively. That means your diagrams can live in .md files next to the code they describe, and they can be generated from the code itself.

This guide walks through a five-minute setup that takes you from "stale Confluence page" to "diagrams that update with every commit." No plugins, no build pipeline rewrites, no diagramming licenses.

What Mermaid actually is (and isn't)

Mermaid is a markdown-like syntax that compiles to SVG or PNG. You write a few lines of text, and a renderer produces a flowchart, sequence diagram, class diagram, ER diagram, Gantt chart, or state diagram. The syntax is intentionally minimal so non-designers can ship a usable diagram in under a minute.

What it isn't: a pixel-perfect illustration tool. You won't get hand-crafted infographic aesthetics. You will get a correct, version-controllable, diff-friendly diagram that renders identically for every reader.

Supported diagram types cover most engineering documentation needs:

Diagram TypeUse Case
FlowchartRequest flow, business logic, decision trees
SequenceAPI calls, service-to-service messaging
ClassObject models, module relationships
ERDatabase schemas
StateLifecycle, status machines
GanttProject timelines, release planning
GitgraphBranching strategy documentation

The 5-minute setup

You don't need a new tool. You need a .md file and one CLI command.

Step 1: Install the Mermaid CLI (1 minute)

The official mermaid-cli wraps headless Chrome and renders .mmd or code-fenced markdown to images. Install it globally:

npm install -g @mermaid-js/mermaid-cli

Verify with mmdc --version. If you hit a Puppeteer error on Linux, install the required Chrome dependencies listed in the official troubleshooting guide.

Step 2: Author your first diagram (2 minutes)

Create a file called auth-flow.mmd:

sequenceDiagram
    participant U as User
    participant A as Auth Service
    participant D as Database
    U->>A: POST /login (email, password)
    A->>D: SELECT user WHERE email=?
    D-->>A: user record
    A->>A: bcrypt.compare(password, hash)
    alt valid credentials
        A->>A: generate JWT (15min)
        A-->>U: 200 OK + token
    else invalid credentials
        A-->>U: 401 Unauthorized
    end

Render it:

mmdc -i auth-flow.mmd -o auth-flow.svg

Open the SVG in any browser. You now have a version-controlled, diff-friendly sequence diagram.

Step 3: Embed in your README (1 minute)

GitHub renders Mermaid code fences natively. Drop the same block into your README, no rendering step required:

```mermaid
sequenceDiagram
    participant U as User
    participant A as Auth Service
    participant D as Database
    U->>A: POST /login
    A->>D: SELECT user
```

For GitLab, Bitbucket, and most docs frameworks, the same syntax works. If your static-site generator uses a different renderer (Docusaurus, MkDocs, Hugo), install the corresponding Mermaid plugin and the result is identical.

Step 4: Automate regeneration (1 minute)

Hand-rendering is fine for a single diagram. For a living architecture document, add an npm script:

{
  "scripts": {
    "docs:diagrams": "find ./diagrams -name '*.mmd' -exec mmdc -i {} -o {}.svg \;"
  }
}

Run npm run docs:diagrams before committing, or wire it into your CI pipeline. A typical GitHub Actions step:

- name: Render diagrams
  run: |
    npm install -g @mermaid-js/mermaid-cli
    find ./diagrams -name '*.mmd' -exec mmdc -i {} -o {}.svg \;
- name: Commit rendered diagrams
  run: |
    git config user.name "docs-bot"
    git config user.email "docs@example.com"
    git add diagrams/*.svg
    git commit -m "docs: regenerate diagrams" || exit 0
    git push

That's the whole loop: code changes, diagram regenerates, README stays accurate.

Generating diagrams from real code

Hand-writing Mermaid works, but it has the same drift problem as hand-drawing. The real win is extraction: read the code, emit the diagram.

Class diagrams from TypeScript

For a class diagram, you need three pieces per class: name, properties, methods. A 30-line Node script with the TypeScript compiler API is enough:

import * as ts from 'typescript';
import * as fs from 'fs';

function emit(sourcePath: string): string {
  const source = fs.readFileSync(sourcePath, 'utf8');
  const ast = ts.createSourceFile(sourcePath, source, ts.ScriptTarget.Latest, true);
  const classes: string[] = [];

  function visit(node: ts.Node) {
    if (ts.isClassDeclaration(node) && node.name) {
      const name = node.name.text;
      const props = node.members
        .filter(ts.isPropertyDeclaration)
        .map(p => `  +${p.name?.getText()} ${(p.type as any)?.getText() ?? 'any'}`);
      const methods = node.members
        .filter(ts.isMethodDeclaration)
        .map(m => `  +${m.name?.getText()}(${m.parameters.map(p => p.name.getText()).join(', ')})`);
      classes.push(`  class ${name} {\n${[...props, ...methods].join('\n')}\n  }`);
    }
    ts.forEachChild(node, visit);
  }

  visit(ast);
  return `classDiagram\n${classes.join('\n')}`;
}

console.log(emit(process.argv[2]));

Run it on any TS file and pipe the output to a .mmd file. The same pattern works for Python with ast, Go with go/parser, and Java with the JavaParser library. The extraction is mechanical; the rendering is free.

Flowcharts from route definitions

For an Express or FastAPI app, iterate over the route registrations and emit a flowchart node per endpoint:

import { Express } from 'express';

const routes: Array<{ method: string; path: string }> = [];

export function track(app: Express) {
  ['get', 'post', 'put', 'delete'].forEach(method => {
    const original = app[method as keyof Express] as any;
    app[method as keyof Express] = function (path: string, ...handlers: any[]) {
      routes.push({ method: method.toUpperCase(), path });
      return original.call(this, path, ...handlers);
    };
  });
}

export function emitRoutes(): string {
  const lines = routes.map(r => `  ${r.path.replace(/[:*]/g, m => m === ':' ? 'id_' : '*')} -->|${r.method}| handler`);
  return `flowchart LR\n  Client --> Router\n  Router -->|\"GET /\" | Root\n${lines.join('\n')}`;
}

Wire track(app) into your bootstrap, and your route diagram updates whenever a developer adds an endpoint.

Sequence diagrams from logs or traces

If you already export OpenTelemetry traces, a sequence diagram is just a transformation: list the spans, group by parent-child, and emit a sequenceDiagram block with one participant per service. A 50-line script against a Jaeger export gives you a real call graph for free.

Keeping diagrams in sync without manual effort

Three patterns work in production:

  1. Generated-on-CI, committed-to-repo. Simplest. CI regenerates SVGs and commits them. Reviewers see diagram diffs in pull requests.
  2. Generated-on-CI, served from CDN. No repo bloat. Docs site pulls the latest SVG from an artifact store. Loses git diff visibility.
  3. Generated-on-demand, rendered in-browser. Pure markdown. The Mermaid JS library renders in the reader's browser. Lightest setup, slowest initial paint, no diagram in README previews on GitHub.

For most teams, option 1 is the right starting point. It is what most of the popular open-source projects use, including the Kubernetes and ArgoCD ecosystems.

A note on complexity

Mermaid scales surprisingly well, but a single diagram with more than roughly 30 nodes starts to hurt readability. If your generated architecture diagram is unprintable, you are documenting the wrong abstraction. Split it. One diagram per bounded context, per service tier, or per request flow. The same extraction script can emit multiple .mmd files filtered by package, namespace, or tag.

Where to go from here

You now have a working setup: Mermaid CLI installed, a script that extracts diagrams from your codebase, and a CI step that keeps the rendered output fresh. The next bottleneck is usually authoring speed: writing the extraction logic for every diagram type you care about takes time, and the syntax for each Mermaid diagram type is a small but real learning curve.

DocPilot handles the generation layer for you. Connect a GitHub repository, point it at the folders or files you want documented, and it produces setup guides, architecture overviews, and API reference docs with embedded Mermaid diagrams that regenerate on every push. The extraction rules for class diagrams, sequence diagrams, and route flowcharts are built in, so you skip the scripting step entirely and get version-controlled, always-current documentation in the time it would have taken to draw a single flowchart by hand. Start with the free tier and wire it into a single repo to see the output for your own codebase.

Ship documentation that keeps up

Try DocPilot on your repository — free for one repo.

Connect your first repository in about a minute. No credit card. DocPilot writes and maintains the documentation from your code.

Read next