Mermaid Diagram in Practice: Sequence, Flowchart, and Block Diagrams for Tech Docs
I started using Mermaid by accident. I was using AI to speed up writing RFCs and technical documents at work, and when I asked for a diagram, the answer came back as Mermaid code instead of a picture. Before that, I drew everything in the diagram canvas inside Lark, where our documents live — fine for the first draft, tedious after the third round of review comments. For a non-engineer reading along: this changes diagram work from dragging shapes into writing three lines of text, so a diagram takes minutes instead of tens of minutes and stays editable forever.
In this article, we'll explore what a mermaid diagram is, the syntax worth memorizing, and a working routine for using it with and without AI.
What a mermaid diagram is
Mermaid is an open-source tool that turns Markdown-like text into a rendered diagram. The whole diagram is plain text, so it lives in your document, in Git, and in a code review diff.
The smallest useful example:
flowchart LR
A[Client] --> B[API]
B --> C[(Database)] flowchart LR
A[Client] --> B[API]
B --> C[(Database)] Three lines, one diagram. LR means left-to-right; TD means top-down. Change one and the whole layout re-flows.
Where this renders without extra setup:
- Lark — insert the Mermaid add-on by typing
/Mermaidon a blank line - GitHub and GitLab — any fenced code block tagged
mermaidrenders automatically - mermaid.live — the free online editor, no account needed
I personally use mermaid.live as a scratchpad and let GitHub render the final version, because the source then sits next to the code it describes.
Three diagram types that cover most technical documents
Sequence diagram — for anything with a request and a response
sequenceDiagram
autonumber
actor U as User
box Aqua Our services
participant API as Order API
participant PAY as Payment Service
end
participant BANK as Bank
U->>+API: POST /orders
API->>+PAY: charge(amount)
PAY->>BANK: authorize
alt authorized
BANK-->>PAY: approved
PAY-->>-API: payment_id
API-->>-U: 201 Created
else declined
BANK-->>PAY: declined
PAY-->>API: error
API-->>U: 402 Payment Required
end sequenceDiagram
autonumber
actor U as User
box Aqua Our services
participant API as Order API
participant PAY as Payment Service
end
participant BANK as Bank
U->>+API: POST /orders
API->>+PAY: charge(amount)
PAY->>BANK: authorize
alt authorized
BANK-->>PAY: approved
PAY-->>-API: payment_id
API-->>-U: 201 Created
else declined
BANK-->>PAY: declined
PAY-->>API: error
API-->>U: 402 Payment Required
end Four things here do most of the work:
-
autonumber— numbers every arrow, and renumbers automatically when you insert a step. This alone is worth switching for; renumbering by hand in a canvas editor is where I used to lose time. -
box Aqua Our services ... end— groups participants under a shaded band. Put the color before the label. Hex colors are not supported here; use a named color,rgb(), orhsl(). -
alt ... else ... end— branches. Useoptfor a single optional path,loopfor repetition,parfor concurrent calls. -
->>+and-->>-— the shorthand foractivateanddeactivate, drawing the block that shows a service is busy.
Flowchart — for decisions and process steps
flowchart TD
Start(["Deploy triggered"]) --> Test{Tests pass?}
Test -- No --> Fail[Notify author]:::bad
Test -- Yes --> Stage[Deploy to staging]
Stage --> Smoke{Smoke test OK?}
Smoke -- No --> Rollback[Roll back]:::bad
Smoke -- Yes --> Prod[Deploy to production]:::good
classDef bad fill:#ffe0e0,stroke:#c00
classDef good fill:#e0ffe6,stroke:#0a0 flowchart TD
Start(["Deploy triggered"]) --> Test{Tests pass?}
Test -- No --> Fail[Notify author]:::bad
Test -- Yes --> Stage[Deploy to staging]
Stage --> Smoke{Smoke test OK?}
Smoke -- No --> Rollback[Roll back]:::bad
Smoke -- Yes --> Prod[Deploy to production]:::good
classDef bad fill:#ffe0e0,stroke:#c00
classDef good fill:#e0ffe6,stroke:#0a0 Shapes carry meaning: [] is a step, {} is a decision, ([]) is a start or end, [()] is a datastore. classDef plus :::name gives you reusable coloring — define the style once, apply it to every failure path.
Use subgraph when you need visual grouping:
flowchart LR
subgraph Edge
CDN --> LB[Load balancer]
end
LB --> App[Application] flowchart LR
subgraph Edge
CDN --> LB[Load balancer]
end
LB --> App[Application] Block diagram — for layered architecture
block-beta
columns 3
frontend["Web App"]:3
api["API Gateway"] auth["Auth Service"] queue["Queue"]
db[("Postgres")]:2 cache[("Redis")] block-beta
columns 3
frontend["Web App"]:3
api["API Gateway"] auth["Auth Service"] queue["Queue"]
db[("Postgres")]:2 cache[("Redis")] Flowcharts lay themselves out automatically, which is usually helpful and occasionally infuriating. Block diagrams give you a grid instead: columns 3 sets the width, and :3 makes a block span three columns.
Try it and watch what changes
Open mermaid.live, paste the flowchart above, then:
- Change
TDtoLR— observe the entire layout rotate with no other edits. - Delete the
classDeflines — observe the colors disappear but the structure survive. Styling and structure are independent. - In the sequence diagram, insert a new arrow in the middle of the
altblock — observe every following number update by itself.
That third one is the moment Mermaid usually sells itself.
Tips that save the most time
- Alias long names.
participant PAY as Payment Servicekeeps the source narrow and the diagram readable. - Comment with
%%. Leave a note for the next reviewer inside the diagram source; it never renders. - Avoid the word
endin a node label. It collides with the block keyword and breaks the diagram. Wrap it in quotes if you must:A["end of flow"]. - One diagram, one message. If a diagram needs a paragraph of explanation, split it into two.
- Keep a starter file. Keep a short
.mmdsnippet for each type and copy from it instead of remembering syntax. Faster than any AI round trip for small edits.
Working with AI — and the part AI gets wrong
The prompt pattern that works:
Draw the checkout flow as a Mermaid sequence diagram.
Participants: User, Order API, Payment Service, Bank.
Include the declined branch.
Output only the Mermaid code, no explanation.Being explicit about diagram type, participants, and "code only" removes most of the back-and-forth.
Two habits matter more than the prompt:
- Verify before pasting. Paste the output into mermaid.live. If it renders there, it will almost always render in your document — subject to the target platform's Mermaid version. AI does invent syntax occasionally, and a broken diagram in a shared RFC is worse than no diagram.
- Edit the source, not the prompt. For small corrections — a renamed service, one extra step — change the line yourself. Asking for a regeneration often reshuffles participant order and loses your earlier fixes.
The honest trade-off: AI is good at extracting structure from a description, and indifferent to layout. Getting a diagram to look right is still your job, and for pixel-level control a drag-and-drop canvas still wins. For everything that lives inside a document and gets revised, text wins.
Extras
- Type
infoin the editor to check the renderer version before using newer syntax. - Diagrams that render locally but not on another platform are almost always a version gap, not a syntax error.
- For platforms without Mermaid support, pre-render to SVG or PNG and embed the image — but keep the source in the document so the next person can edit it.
Takeaways
- A mermaid diagram is text, so it belongs in the document and survives review cycles.
-
autonumber,alt,box,subgraph, andclassDefcover most real documentation needs. - Verify every AI-generated diagram in mermaid.live before it reaches a shared document.