Mermaid Diagrams: When Text Becomes Visual

· 8 min read

Mermaid Diagrams

Mermaid turns text into diagrams. Write A --> B and get a flowchart. No Visio. No draw.io. No PNG files that nobody can edit six months later.

Why Mermaid Matters

  1. Diagrams as code - Store in Git, review in PRs, version control everything
  2. Readable source - Text format is understandable before rendering
  3. No binary files - Git diffs work, no merge conflicts on images
  4. Fast - Type faster than dragging boxes around
  5. LLM-native - AI models generate and modify Mermaid fluently

Markdown + Mermaid: A Natural Pair

Mermaid isn’t a separate format - it lives inside Markdown. You embed diagrams using fenced code blocks:

# My Documentation

Some text here.

```mermaid
graph TD
    A --> B
```

More text here.

Why this matters:

  • One file format for text AND diagrams
  • Markdown processors recognize ```mermaid blocks and render them
  • GitHub, GitLab, Notion, Obsidian - all support Mermaid in Markdown natively
  • No importing, no linking to external files

The workflow:

  1. Write documentation in Markdown
  2. Need a diagram? Add a ```mermaid code block
  3. Write diagram as text
  4. Render shows text + diagrams together

It’s why this series groups them together: Markdown for structure, Mermaid for visuals, both as plain text.

LLMs and Mermaid: Visual Thinking Made Easy

LLMs excel at generating Mermaid diagrams because it’s structured text, not pixel manipulation.

Why it works:

  • Mermaid syntax is in training data (GitHub, documentation, forums)
  • Logical structure maps to diagram structure
  • No ambiguity - syntax errors are clear
  • Models can iterate and refine diagrams through text

The workflow:

You: "Create a flowchart for user authentication"
LLM: [Generates Mermaid code]
You: "Add password reset flow"
LLM: [Modifies existing Mermaid code]

No screenshots. No “can you make this arrow point there?” Just text edits.

Prompt tip: Be specific about diagram type:

  • “Create a Mermaid flowchart showing…”
  • “Draw a sequence diagram with Mermaid for…”
  • “Generate a Mermaid class diagram representing…”

Diagram Types

Flowchart

graph TD A[Start] --> B{Decision} B -->|Yes| C[Action 1] B -->|No| D[Action 2] C --> E[End] D --> E

Sequence Diagram

sequenceDiagram User->>API: Login Request API->>DB: Validate Credentials DB-->>API: Success API-->>User: JWT Token

Class Diagram

classDiagram class User { +String name +String email +login() +logout() } class Admin { +deleteUser() } User <|-- Admin

State Diagram

stateDiagram-v2 [*] --> Idle Idle --> Processing: Start Processing --> Success: Complete Processing --> Failed: Error Success --> [*] Failed --> Idle: Retry

Entity Relationship Diagram

erDiagram USER ||--o{ ORDER : places ORDER ||--|{ ORDER_ITEM : contains PRODUCT ||--o{ ORDER_ITEM : includes

Git Graph

gitGraph commit branch feature checkout feature commit commit checkout main merge feature commit

Core Syntax

Flowchart Basics

Direction: graph TD (top-down), graph LR (left-right), graph BT (bottom-top), graph RL (right-left)

Node shapes:

  • A[Rectangle] → Rectangle
  • B(Rounded) → Rounded rectangle
  • C{Diamond} → Diamond (decision)
  • D((Circle)) → Circle
  • E>Asymmetric] → Asymmetric shape

Connections:

  • A --> B → Arrow
  • A --- B → Line
  • A -.-> B → Dotted arrow
  • A ==> B → Thick arrow
  • A -->|Label| B → Labeled arrow

Sequence Diagram Syntax

Participants: participant Name or auto-detected from interactions

Arrows:

  • A->>B → Solid arrow
  • A-->>B → Dotted arrow
  • A-xB → Cross at end
  • A-)B → Open arrow

Notes: Note right of A: Text or Note over A,B: Text

Activation: activate A and deactivate A

Class Diagram Syntax

Visibility:

  • + Public
  • - Private
  • # Protected
  • ~ Package

Relationships:

  • <|-- Inheritance
  • *-- Composition
  • o-- Aggregation
  • --> Association
  • ..> Dependency

Common Patterns

API Flow

sequenceDiagram Client->>+Server: POST /api/data Server->>+Database: INSERT query Database-->>-Server: Success Server-->>-Client: 201 Created

State Machine

stateDiagram-v2 [*] --> Draft Draft --> Review: Submit Review --> Approved: Accept Review --> Draft: Reject Approved --> Published: Deploy Published --> [*]

System Architecture

graph TB User[User] --> LB[Load Balancer] LB --> API1[API Server 1] LB --> API2[API Server 2] API1 --> DB[(Database)] API2 --> DB API1 --> Cache[(Redis)] API2 --> Cache

Common Pitfalls

  1. Syntax sensitivity - Indentation matters in complex diagrams
  2. Special characters - Use quotes for labels with special chars: A["Text with: special"]
  3. Escape quotes - Use #quot; inside quoted text
  4. Node IDs - Can’t start with numbers, use alphanumeric
  5. Direction - Choose direction before building complex diagrams

Tools

Live editors:

IDE Support:

  • VSCode: “Markdown Preview Mermaid Support” extension
  • JetBrains: Built-in Mermaid support
  • Obsidian: Native Mermaid rendering

CI/CD Integration:

  • GitHub: Native Mermaid rendering in Markdown
  • GitLab: Native support in Markdown files
  • mermaid-cli: Generate PNG/SVG from command line

Documentation:

The Philosophy

Diagrams should evolve with code. When your architecture changes, your diagram should change in the same commit. With Mermaid:

  • Diagrams live next to code
  • Pull requests show diagram changes
  • Documentation stays synchronized
  • No “the diagram is out of date” excuses

Version control for visuals. Finally.

See It In Action

Here are complex examples showing raw Mermaid and their rendered output:

Example 1: Authentication Flow with Error Handling

Raw:

```mermaid
sequenceDiagram
    participant U as User
    participant A as Auth Service
    participant D as Database
    participant C as Cache

    U->>+A: POST /login
    A->>+C: Check session
    C-->>-A: Not found
    A->>+D: Validate credentials
    alt Credentials valid
        D-->>A: User data
        A->>C: Store session
        A-->>U: 200 + JWT
    else Invalid credentials
        D-->>-A: Error
        A-->>U: 401 Unauthorized
    end
    deactivate A
```

Renders as:

sequenceDiagram participant U as User participant A as Auth Service participant D as Database participant C as Cache U->>+A: POST /login A->>+C: Check session C-->>-A: Not found A->>+D: Validate credentials alt Credentials valid D-->>A: User data A->>C: Store session A-->>U: 200 + JWT else Invalid credentials D-->>-A: Error A-->>U: 401 Unauthorized end deactivate A

Example 2: Feature Flag Decision Flow

Raw:

```mermaid
graph TD
    Start[User Request] --> Check{Feature Flag Enabled?}
    Check -->|Yes| NewFeature[New Feature Path]
    Check -->|No| OldFeature[Legacy Path]

    NewFeature --> Log1[Log: new_feature_used]
    OldFeature --> Log2[Log: legacy_path_used]

    Log1 --> Response[Return Response]
    Log2 --> Response

    Response --> End[End]

    style NewFeature fill:#90EE90
    style OldFeature fill:#FFB6C1
```

Renders as:

graph TD Start[User Request] --> Check{Feature Flag Enabled?} Check -->|Yes| NewFeature[New Feature Path] Check -->|No| OldFeature[Legacy Path] NewFeature --> Log1[Log: new_feature_used] OldFeature --> Log2[Log: legacy_path_used] Log1 --> Response[Return Response] Log2 --> Response Response --> End[End] style NewFeature fill:#90EE90 style OldFeature fill:#FFB6C1

Example 3: Database Schema Relationships

Raw:

```mermaid
erDiagram
    USER ||--o{ POST : creates
    USER ||--o{ COMMENT : writes
    POST ||--o{ COMMENT : has
    POST }o--|| CATEGORY : belongs_to
    POST }o--o{ TAG : tagged_with

    USER {
        int id PK
        string email UK
        string name
        datetime created_at
    }

    POST {
        int id PK
        int user_id FK
        int category_id FK
        string title
        text content
        datetime published_at
    }

    COMMENT {
        int id PK
        int user_id FK
        int post_id FK
        text content
        datetime created_at
    }
```

Renders as:

erDiagram USER ||--o{ POST : creates USER ||--o{ COMMENT : writes POST ||--o{ COMMENT : has POST }o--|| CATEGORY : belongs_to POST }o--o{ TAG : tagged_with USER { int id PK string email UK string name datetime created_at } POST { int id PK int user_id FK int category_id FK string title text content datetime published_at } COMMENT { int id PK int user_id FK int post_id FK text content datetime created_at }

Example 4: CI/CD Pipeline States

Raw:

```mermaid
stateDiagram-v2
    [*] --> CodePushed
    CodePushed --> BuildRunning: Trigger CI

    BuildRunning --> TestsRunning: Build Success
    BuildRunning --> Failed: Build Failed

    TestsRunning --> Deploying: Tests Pass
    TestsRunning --> Failed: Tests Failed

    Deploying --> Staging: Deploy to Staging
    Staging --> Production: Manual Approval
    Staging --> Failed: Deploy Failed

    Production --> [*]: Success
    Failed --> [*]: Notify Team

    note right of BuildRunning
        Runs linters,
        type checks,
        compiles code
    end note

    note right of TestsRunning
        Unit tests,
        Integration tests,
        E2E tests
    end note
```

Renders as:

stateDiagram-v2 [*] --> CodePushed CodePushed --> BuildRunning: Trigger CI BuildRunning --> TestsRunning: Build Success BuildRunning --> Failed: Build Failed TestsRunning --> Deploying: Tests Pass TestsRunning --> Failed: Tests Failed Deploying --> Staging: Deploy to Staging Staging --> Production: Manual Approval Staging --> Failed: Deploy Failed Production --> [*]: Success Failed --> [*]: Notify Team note right of BuildRunning Runs linters, type checks, compiles code end note note right of TestsRunning Unit tests, Integration tests, E2E tests end note

Quick Reference

```mermaid
graph TD
    A[Box] --> B(Rounded)
    B --> C{Diamond}
    C -->|Yes| D[Result]
```

```mermaid
sequenceDiagram
    A->>B: Message
    B-->>A: Response
```

```mermaid
classDiagram
    class Name {
        +field
        +method()
    }
```

```mermaid
stateDiagram-v2
    State1 --> State2
    State2 --> [*]
```

That’s the core. Text in, diagrams out.


Previous: Markdown Essentials Next: Marp Presentations - Markdown becomes slides.

Part of the VSCode Content Creator workflow.