Guide

How to draw architecture diagrams in Mermaid (subgraph syntax)

Step-by-step tutorial for using Mermaid's subgraph syntax to draw layered architecture diagrams — clusters, cross-boundary edges, and bidirectional connectors.

Follow the workflow, open the example in the editor, then export or save the cleaner result.

At a glance

A practical walkthrough for engineers who want to express system architecture in plain Mermaid. Each section adds one syntax feature, so by the end of the page a three-tier platform diagram reads naturally and renders cleanly.

Start with a single subgraphConnect two subgraphs with a cross-boundary edgePoint an edge from a whole clusterUse bidirectional and dotted connectors for two-way relationshipsAdd a second line with <br/>Avoid the syntax that used to break flowchart subgraphQuick-start template
Rendered proof
A three-tier platform diagram using subgraph clusters, a cluster-as-endpoint edge, and bidirectional connectors.
Theme · Atlas
Open this diagram in editor
User Channels Runtime · Local Node.js Ecosystem WhatsAppTelegramEmail GatewayState · Routing DECISION AgentReasoning · Execution Memory Skills LoaderOn-demand Skill Registry3,000+ skills AI ModelsCLI
View Mermaid sourcePlain-text diagram syntax — copy or edit directly.
diagram.mmd
1flowchart LR
2 subgraph Channels["User Channels"]
3 direction TB
4 WhatsApp["WhatsApp"]
5 Telegram["Telegram"]
6 Email["Email"]
7 end
8
9 subgraph Runtime["Runtime · Local Node.js"]
10 direction TB
11 Gateway["Gateway<br/>State · Routing"]
12 Agent["Agent<br/>Reasoning · Execution"]
13 Memory["Memory<br/>Persistent Notes"]
14 Skills["Skills Loader<br/>On-demand"]
15 Gateway --> Agent
16 Agent --> Memory
17 Agent --> Skills
18 end
19
20 subgraph Ecosystem["Ecosystem"]
21 direction TB
22 Registry["Skill Registry<br/>3,000+ skills"]
23 Models["AI Models<br/>Claude · GPT · Local"]
24 CLI["CLI<br/>search · install · publish"]
25 end
26
27 Channels ==> Gateway
28 Agent <--> Models
29 Skills <--> Registry
30 Registry <-.-> CLI
Pre-rendered examples

Theme and animation variants

Rendered proof
The same architecture diagram in a documentation-friendly Atlas theme.
Theme · Atlas
Open variant in editor
User Channels Runtime · Local Node.js Ecosystem WhatsAppTelegramEmail GatewayState · Routing DECISION AgentReasoning · Execution Memory Skills LoaderOn-demand Skill Registry3,000+ skills AI ModelsCLI
Rendered proof
The same architecture diagram in an editorial Atelier theme.
Theme · Atelier
Open variant in editor
User Channels Runtime · Local Node.js Ecosystem WhatsApp Telegram Email Gateway State · Routing DECISION AgentReasoning · Execution Memory Persistent Notes Skills Loader On-demand Skill Registry 3,000+ skills AI Models Claude · GPT · Local CLI search · install · publish
Rendered proof
A simpler two-cluster shape — Frontend handing off to Backend through one cross-boundary edge.
Theme · Modern
Open variant in editor
FRONTEND BACKEND Dashboard Submission Form Gateway Service Database

Start with a single subgraph

A subgraph in Mermaid is a labelled boundary around a set of nodes. It is the simplest way to communicate that several pieces belong to the same module, service, or layer. Each subgraph has an id (used for cross-references) and an optional bracket label for the visible title. Inside the block, declare nodes the same way as a normal flowchart.

  • Use the bracket form (`subgraph Frontend["Frontend"]`) when you want a different display title from the id
  • Add `direction TB` or `direction LR` inside the block to suggest how the nodes should stack
  • Standalone node declarations like `UI["Dashboard"]` are valid even without an outgoing edge — useful for visual anchors

Connect two subgraphs with a cross-boundary edge

Once a second subgraph exists, draw the relationship between modules with an edge that crosses the boundary. The edge can reference any node by id, regardless of which subgraph it lives in. Cross-boundary edges are the signal that turns a flat list of clusters into an actual architecture story — the renderer can then arrange the clusters along the handoff direction.

Point an edge from a whole cluster

Mermaid lets a subgraph id appear on either side of an edge, which reads as "the entire cluster connects to this node". This is useful when many components in a module funnel into the same downstream service and listing every individual edge would be noisy. The renderer routes the edge from a representative member of the cluster to the target.

  • `Channels ==> Gateway` — the User Channels cluster fans into the Gateway
  • `Runtime -.-> Note` — a side note attached to the Runtime cluster
  • Cluster-as-endpoint works for the source side, the target side, or both

Use bidirectional and dotted connectors for two-way relationships

An LLM agent that calls a model and waits for a response is a two-way relationship, not a one-way arrow. Mermaid supports `<-->` for bidirectional solid, `<-.->` for bidirectional dotted, and `<==>` for bidirectional thick. Dotted variants read well for asynchronous traffic, registry lookups, or weaker dependencies that you still want to make visible.

Add a second line with <br/>

Architecture nodes often need a short caption under the headline — the role, the storage backend, the deployment target. Put the headline first, then `<br/>` (Mermaid's official line break), then the caption. The renderer treats the second line as a smaller subtitle and keeps the node's overall footprint compact. Inline HTML beyond `<br/>` is stripped, so paste-from-styled-source still produces clean labels.

Avoid the syntax that used to break flowchart subgraph

Three patterns commonly broke older Mermaid renderers and produced the infamous `Cannot set properties of undefined (setting 'rank')` error: standalone node declarations inside a subgraph (no outgoing edge), an edge endpoint that referenced a subgraph id, and labels with surrounding quotes. All three render correctly in the editor — paste any of them and they come out as written.

  • `Foo["Bar"]` on its own line — kept as a node, not silently dropped
  • `Cluster ==> Node` — routed to the cluster's representative member
  • `subgraph Foo["Quoted Title"]` — quotes are unwrapped in the visible title

Quick-start template

If a teammate asks for a Mermaid architecture diagram and there is no time to write one from scratch, paste the example below into the editor. It demonstrates three subgraphs, a cluster-as-endpoint edge, two bidirectional connectors, and multi-line labels. Adjust the labels to your domain — the structure is reusable across most platform-style architectures.

Guide FAQ

Questions about this workflow

Do all nodes inside a subgraph need an edge?

No. A node declared on its own line — `Foo["Bar"]` — still belongs to the surrounding subgraph and renders as a labelled box. This is useful for showing module members that exist but don't participate in the depicted flow.

Can a subgraph id be used directly as an edge endpoint?

Yes. `Channels ==> Gateway` reads as "the User Channels cluster fans into the Gateway". The renderer routes the edge from a representative member of the cluster, so the architectural intent reads correctly even without listing every individual member's edge.

What's the right way to add a subtitle to a node?

Put `<br/>` between the headline and the subtitle inside the bracket label, like `Gateway["Gateway<br/>State · Routing"]`. Other inline HTML such as `<small>` or `<b>` is stripped — the cleaner label is what ends up in the rendered SVG.

How do I show a two-way relationship between modules?

Use a bidirectional connector — `<-->` for solid, `<-.->` for dotted, `<==>` for thick. Dotted bidirectional reads well for asynchronous lookups (skills registry, model providers); solid reads well for tight request-response pairs (agent ↔ service).

Does Beauty Diagram support classDef styling?

The editor focuses on theme-driven visual hierarchy, so `classDef` and `class` declarations are accepted as syntax but not honoured for styling. Switch themes in the editor instead — the same Mermaid source will read differently across themes without rewriting the source.