GraphViz Reference
GraphViz graph description language. Directed and undirected graphs, clusters, ranking, edge styling, and layout engines.
Directed Graphs
digraph {
rankdir=LR
A -> B -> C
A -> D -> C
}
rankdir=LR flows left to right. Default is TB (top to bottom).
digraph {
node [fontname="Helvetica" fontsize=11]
server [label="Web Server" shape=box style=filled fillcolor="#89b4fa" fontcolor="#1e1e2e"]
db [label="PostgreSQL" shape=cylinder style=filled fillcolor="#a6e3a1" fontcolor="#1e1e2e"]
server -> db [label="SQL" color="#f5c2e7"]
}
Undirected Graphs
graph and -- instead of digraph and →graph {
A -- B
B -- C
A -- C
}
Node Shapes
digraph {
a [shape=box label="box"]
b [shape=ellipse label="ellipse (default)"]
c [shape=diamond label="diamond"]
d [shape=circle label="circle"]
e [shape=cylinder label="cylinder"]
f [shape=hexagon label="hexagon"]
g [shape=parallelogram label="parallelogram"]
h [shape=record label="{record|with|fields}"]
}
Subgraphs (Clusters)
digraph {
subgraph cluster_network {
label="Network Layer"
style=filled
color="#313244"
fontcolor="#cdd6f4"
fw [label="Firewall"]
lb [label="Load Balancer"]
fw -> lb
}
subgraph cluster_app {
label="Application Layer"
style=filled
color="#313244"
fontcolor="#cdd6f4"
api [label="API"]
worker [label="Worker"]
}
lb -> api
api -> worker
}
Cluster names must start with cluster_ to render as a box.
Ranking and Alignment
digraph {
rankdir=TB
{rank=same; A; B; C}
start -> A
start -> B
start -> C
A -> end
B -> end
C -> end
}
Edge Styling
digraph {
A -> B [style=dashed color=red]
A -> C [style=bold penwidth=2.0]
A -> D [arrowhead=diamond label="inherits"]
B -> D [style=dotted constraint=false]
}
constraint=false prevents the edge from affecting rank ordering.
CLI Commands
dot -Tsvg graph.dot -o graph.svg
dot -Tpng graph.dot -o graph.png
neato -Tsvg graph.dot -o graph.svg # Spring model (undirected)
fdp -Tsvg graph.dot -o graph.svg # Force-directed
circo -Tsvg graph.dot -o graph.svg # Circular layout
twopi -Tsvg graph.dot -o graph.svg # Radial layout
sfdp -Tsvg graph.dot -o graph.svg # Large graph force-directed
Kroki Integration
[graphviz,target=infra-graph,format=svg]
....
digraph {
rankdir=LR
client -> firewall -> server -> database
}
....
Record-Based Nodes
digraph {
node [shape=record]
user [label="{User|+id: int\l+name: string\l+email: string\l|+save()\l+delete()\l}"]
session [label="{Session|+token: string\l+expires: datetime\l}"]
user -> session [label="has_many"]
}
The \l left-aligns text within a record field.
HTML Labels (Structured Node Internals)
node [shape=none]
ise [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="5"
BGCOLOR="#3a1e1e" COLOR="#f38ba8">
<TR><TD COLSPAN="2" BGCOLOR="#4a2a2a">
<B><FONT COLOR="#f38ba8">ise-01</FONT></B>
</TD></TR>
<TR>
<TD PORT="radius"><FONT COLOR="#bac2de">RADIUS</FONT></TD>
<TD><FONT COLOR="#89dceb">:1812</FONT></TD>
</TR>
</TABLE>
>]
PORT="radius" names the cell. Edges target it: ise:radius → switch:g1.
switch [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="6"
BGCOLOR="#1e3e3a" COLOR="#94e2d5">
<TR><TD COLSPAN="4" BGCOLOR="#2a4e4a">
<B><FONT COLOR="#94e2d5">3560-CX</FONT></B>
</TD></TR>
<TR>
<TD PORT="g1"><FONT POINT-SIZE="1"> </FONT></TD>
<TD PORT="g2"><FONT POINT-SIZE="1"> </FONT></TD>
<TD PORT="g3"><FONT POINT-SIZE="1"> </FONT></TD>
<TD PORT="g4"><FONT POINT-SIZE="1"> </FONT></TD>
</TR>
</TABLE>
>]
POINT-SIZE="1" makes spacer cells invisible. Cables target switch:g1 etc. and land at different horizontal positions.
Cable Labels (Cisco-Style Interface Labels)
vyos -> switch:g1 [
taillabel=<<FONT COLOR="#89b4fa" POINT-SIZE="8">eth1</FONT>>
headlabel=<<FONT COLOR="#94e2d5" POINT-SIZE="8">Gi0/1</FONT>>
label=<<FONT COLOR="#585b70" POINT-SIZE="7">Trunk · All VLANs</FONT>>
labeldistance=2.0
labelangle=25
color="#89b4fa"
penwidth=2
]
-
taillabel— interface name at source (device end) -
headlabel— switch port at destination -
label— protocol/subnet on the cable middle -
labeldistance— distance from node (1.5–3.0) -
labelangle— tilt alongside cable (15–30)
HTML <FONT> gives bare colored text without boxes.
splines=ortho breaks headlabel/taillabel placement. Use splines=true for cable labels, or xlabel with ortho.
|
HA Relationships
vyos01 -> vyos02 [
label=<<FONT COLOR="#f38ba8" POINT-SIZE="7">VRRP</FONT>>
dir=both
style=dashed
color="#f38ba8"
constraint=false
]
constraint=false prevents HA edges from distorting the rank layout.
kvm01 -> ise [style=dotted, color="#585b70", arrowhead=none]
Spline Routing
digraph G {
splines=true // Curved — accurate label placement
splines=ortho // Right-angle — breaks headlabel/taillabel
nodesep=0.8 // Horizontal node spacing
ranksep=1.0 // Vertical rank spacing
concentrate=true // Merge parallel edges
newrank=true // Enable rank=same inside clusters
}
Batch Rendering and Verification
for f in docs/modules/ROOT/examples/diagrams/lab/graphviz/*.dot; do
out="/tmp/$(basename "${f%.dot}").svg"
if dot -Tsvg "$f" -o "$out" 2>&1; then
printf "✅ %-45s → %s\n" "$(basename "$f")" "$out"
else
printf "❌ %-45s FAILED\n" "$(basename "$f")"
fi
done
dot -Tsvg $(find -name '07-full-topology.dot') -o /tmp/full-topology.svg
grep -h 'include::example\$' $(find -name 'graphviz-fundamentals.adoc') | \
awk -F'[$\\[\\]]' '{print $2}' | while read f; do
match=$(find docs/modules/ROOT/examples -name "$(basename "$f")")
printf "%-55s %s\n" "$f" "${match:-MISSING}"
done
Catppuccin Mocha Palette
| Color | Hex | Use |
|---|---|---|
Base |
|
|
Surface0 |
|
Default fill |
Surface1 |
|
Header rows |
Surface2 |
|
Borders, muted |
Text |
|
Primary font |
Red |
|
Identity / security |
Green |
|
Endpoints / auth |
Blue |
|
Network / WAN |
Peach |
|
PKI / secrets |
Mauve |
|
Directory / compute |
Teal |
|
DNS |
Sapphire |
|
Wireless |
Yellow |
|
Warnings / VIPs |
See Also
-
Kroki — renders GraphViz in Antora builds
-
Diagrams as Code — tool selection guide