GraphViz Reference

GraphViz graph description language. Directed and undirected graphs, clusters, ranking, edge styling, and layout engines.

Directed Graphs

Basic digraph with nodes and edges
digraph {
    rankdir=LR
    A -> B -> C
    A -> D -> C
}

rankdir=LR flows left to right. Default is TB (top to bottom).

Node attributes — shape, color, label
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

Undirected graph — uses graph and -- instead of digraph and
graph {
    A -- B
    B -- C
    A -- C
}

Node Shapes

Common shape reference
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)

Cluster subgraphs for logical grouping
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

Force nodes to the same rank (horizontal alignment)
digraph {
    rankdir=TB
    {rank=same; A; B; C}
    start -> A
    start -> B
    start -> C
    A -> end
    B -> end
    C -> end
}

Edge Styling

Edge attributes — style, color, weight, arrowhead
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

Render to SVG and PNG
dot -Tsvg graph.dot -o graph.svg
dot -Tpng graph.dot -o graph.png
Other layout engines
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 in AsciiDoc via Kroki
[graphviz,target=infra-graph,format=svg]
....
digraph {
    rankdir=LR
    client -> firewall -> server -> database
}
....

Record-Based Nodes

Struct-like records for data schemas
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 with PORT cells for edge targeting
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.

Invisible port cells — spread cables across a switch face
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)

Interface labels on the wire — not in boxes
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

VRRP/SSO peer links without vertical distortion
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.

KVM "hosts" relationships — dotted, no arrowhead
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

Render all .dot files in a directory
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
Render directly from source (no heredoc needed)
dot -Tsvg $(find -name '07-full-topology.dot') -o /tmp/full-topology.svg
Audit all includes in a partial — verify no broken references
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

#1e1e2e

bgcolor

Surface0

#313244

Default fill

Surface1

#45475a

Header rows

Surface2

#585b70

Borders, muted

Text

#cdd6f4

Primary font

Red

#f38ba8

Identity / security

Green

#a6e3a1

Endpoints / auth

Blue

#89b4fa

Network / WAN

Peach

#fab387

PKI / secrets

Mauve

#cba6f7

Directory / compute

Teal

#89dceb

DNS

Sapphire

#74c7ec

Wireless

Yellow

#f9e2af

Warnings / VIPs

See Also