TRANSLATION

Mermaid syntax for network topology: the full reference

Every piece of Mermaid flowchart syntax a network engineer needs, with the escaping rules, the styling that separates tiers, the renderer differences between GitHub and Obsidian, and the version bug that draws an arrowhead on a link you wrote as undirected.

Reading this, you will:
  • Write any campus or datacenter topology in Mermaid without looking up syntax.
  • Escape hostnames and descriptions that contain characters Mermaid treats as syntax.
  • Know which features render in GitHub, GitLab, Obsidian, and VS Code before you rely on them.

This is the reference version. The diagrams as code article covers the grammar in five minutes and why any of this is worth doing. This one is what you open when a diagram will not render, or when you need a shape you have not used before.

Ids and labels are different things

Every node has an id, which Mermaid parses, and optionally a label, which the reader sees.

core1["core-sw01.campus.example.com"]

In that line, core1 is the id and the quoted text after it is the label.

Ids cannot contain dots, dashes, spaces, or most punctuation. Hostnames contain all of those, which is why generating a diagram from real data always includes a sanitizing step:

def node_id(hostname):
    return hostname.replace(".", "_").replace("-", "_")

Labels have no such restriction as long as they are quoted, so put the real hostname in the label and let the id be whatever the sanitizer produces.

Direction

The first line sets the layout direction.

Write Layout
flowchart TD Top down. The default for tiered topology.
flowchart LR Left to right. Good for paths and flows.
flowchart BT Bottom up.
flowchart RL Right to left.

graph TD is the older keyword and still works, but flowchart is current and supports shapes graph does not.

The link operator carries the meaning, so pick it on purpose.

Write Draws Use for
a --- b Solid, no arrow A physical cable.
a === b Thick, no arrow An uplink or port channel.
a -.- b Dotted, no arrow A standby or backup path.
a --> b Solid with arrow Direction that means something, such as traffic or a decision.
a ==> b Thick with arrow A primary directional path.
a -.-> b Dotted with arrow A conditional or fallback flow.
a <--> b Arrows both ends An explicitly bidirectional relationship.
a --x b Cross at the end A blocked or dropped path.
a --o b Circle at the end A terminated or open end.

Length is controlled by how many dashes you type. a ---- b pushes the two nodes further apart than a --- b, which is the only layout control the flowchart renderer gives you. Use it when the layout engine crowds a diagram.

Text between pipes goes on the link:

core1 ---|"Te1/1/1 to Gi0/0/0"| edge1

There is an older form, core1 -- Te1/1/1 --- edge1, which reads badly with interface names and breaks as soon as the label has punctuation. Use the pipes.

The link styles worth knowing
Rendering diagram…
View diagram source - it's just text (Mermaid). Diagrams-as-code is how modern network docs work; the flagship course has a free module on it.
flowchart LR
  acc["acc-sw01"]
  core_a["core-sw01"]
  core_b["core-sw02"]
  fw["fw-edge01"]
  acc ---|"Gi1/0/48"| core_a
  acc -.-|"standby uplink"| core_b
  core_a ===|"Po1, 2x10G"| core_b
  core_a -->|"default route"| fw
The link styles worth knowing

Node shapes

Shapes carry meaning cheaply, so a reader can tell a router from a subnet without a legend.

Write Shape Conventional use
a["text"] Rectangle A device.
a("text") Rounded A service or process.
a(["text"]) Stadium A start or end point.
a[["text"]] Subroutine A subsystem drawn elsewhere.
a[("text")] Cylinder A database or store.
a(("text")) Circle A cloud, an internet edge, or a peering point.
a{"text"} Diamond A decision.
a{{"text"}} Hexagon A boundary, such as a firewall or a WAN edge.
a[/"text"/] Parallelogram Input or output.

The backslash shapes, the alternate parallelogram and both trapezoids, are a problem in any file where the diagram sits inside a JavaScript template literal, because the backslash is consumed before Mermaid sees it. Avoid them in MDX and JSX. Multi-line labels use <br/>:

core1["core-sw01<br/>10.10.0.11<br/>Catalyst 9500"]

Escaping

Wrap every label in quotes as a default habit. That handles spaces, slashes, and most punctuation. For characters the parser still treats as syntax, use entity codes:

Character Write
" #quot;
# #35;
( and ) Safe inside quotes.
< and > #lt; and #gt;

An interface description such as uplink (primary) to "core" becomes:

acc1 ---|"uplink (primary) to #quot;core#quot;"| core1

If a diagram is generated from device data, put the escaping in the generator itself. Port descriptions are free text and somebody will eventually put a quote in one.

Grouping with subgraphs

A subgraph draws a box around nodes, which is how you show a site, a closet, or a tier:

subgraph idf2["Floor 2 IDF"]
  acc1["acc-sw01"]
  acc2["acc-sw02"]
end

The id is required if you want to link to the group as a whole. Subgraphs can carry their own direction, which is useful when the outer diagram is top down and one group reads better sideways:

subgraph core["Core"]
  direction LR
  core1["core-sw01"]
  core2["core-sw02"]
end
Three tiers as subgraphs
Rendering diagram…
View diagram source - it's just text (Mermaid). Diagrams-as-code is how modern network docs work; the flagship course has a free module on it.
flowchart TD
  subgraph edge["WAN edge"]
    rtr["rtr-edge01"]
    fw{{"fw-edge01"}}
  end
  subgraph core["Core"]
    direction LR
    c1["core-sw01"]
    c2["core-sw02"]
  end
  subgraph idf2["Floor 2 IDF"]
    a1["acc-sw01"]
    a2["acc-sw02"]
  end
  rtr --- fw
  fw --- c1
  fw --- c2
  c1 === c2
  c1 --- a1
  c2 --- a2
  a1 --- a2
Three tiers as subgraphs

Styling a tier

Two mechanisms do different jobs.

Define a style with classDef, then apply it to nodes with class:

classDef core fill:#1f3a5f,stroke:#4a90d9,color:#fff
classDef access fill:#2a2a2a,stroke:#666,color:#ddd
class c1,c2 core
class a1,a2 access

There is a shorthand for a single node, c1:::core, which is convenient and easy to miss when reading someone else’s diagram.

linkStyle targets links by index, counting from zero in the order they appear in the source:

linkStyle 0,1 stroke:#d9534f,stroke-width:3px
linkStyle default marker-end:none

Index-based targeting is fragile. Insert a link in the middle of the diagram and every later index shifts. In generated diagrams, emit the linkStyle lines from the same loop that emits the links, so the indexes cannot drift apart.

Comments

A line starting with %% is a comment:

%% Generated by tools/generate_diagram.py. Do not edit by hand.
flowchart TD

For a generated file, that header is worth having. It tells the next person why their hand edit disappeared.

Mermaid 11.4.x converts flowchart edges with an end marker defaulting to an arrow point, and only overrides it for the arrow, circle, and cross link types. An open link, a --- b, matches none of those cases, so it keeps the default arrowhead. A physical topology written correctly with --- renders as though every cable has a direction.

Upstream fixed this in 11.5.0. If you are pinned to an older version, override the end marker for the whole diagram:

flowchart TD
  a["acc-sw01"]
  b["core-sw01"]
  a --- b
  linkStyle default marker-end:none

Then restore the arrowhead on the links that should have one, by index. This is worth knowing before you conclude your own syntax is wrong, because the diagram renders without an error and simply says something you did not write.

What renders where

Each host ships its own Mermaid version, so support is not uniform.

Renderer Notes
GitHub Renders in Markdown files, issues, and pull requests. Conservative version.
GitLab Same idea, sometimes a different version than GitHub.
Obsidian Renders in preview. Version tracks the app release.
VS Code Needs an extension. Usually the newest of the group.
Notion Code block set to Mermaid. Limited to common diagram types.

Flowcharts, sequence diagrams, and state diagrams work everywhere. Newer node shapes, per-diagram config blocks, and alternate layout engines do not. If the same file has to render in more than one of these, write for the oldest one in the set and check it there rather than in the newest.

Where to go from here

To generate this from real device output instead of typing it, the LLDP article covers the parsing, and the network diagram generator runs it in your browser with no account.

The graded version, with a test suite over the generator functions, is in the free Mermaid lesson.