If you've ever needed to turn a list of nodes and connections into a clean, readable diagram, the Graphviz DOT language is one of the most reliable ways to do it. It's a plain-text graph description language that lets you define nodes, edges, and their properties then renders them into visual diagrams automatically. Whether you're mapping out a software architecture, visualizing data relationships, or documenting system flows, having a solid syntax reference for DOT saves hours of trial and error.

This reference covers the core syntax rules, practical examples, common pitfalls, and tips so you can write DOT code confidently without constantly searching for answers.

What is the DOT language, and how does Graphviz use it?

DOT is a declarative language created as part of the Graphviz (Graph Visualization Software) project originally developed at AT&T Labs. You describe a graph's structure in plain text, and Graphviz tools like dot, neato, fdp, and circo render it into formats like SVG, PNG, or PDF.

A DOT file describes three main things:

  • Nodes individual elements in the graph
  • Edges connections between nodes
  • Attributes visual and structural properties like color, shape, and label text

Because DOT files are plain text, they work well with version control systems, automated pipelines, and scripting. You can find more about the project's background in the official Graphviz documentation.

What does the basic syntax structure look like?

A DOT graph starts with either digraph for directed graphs (with arrow edges) or graph for undirected graphs (with plain lines). Everything else goes inside curly braces.

Here's the skeleton:

digraph {
 A -> B
 B -> C
}

For an undirected graph:

graph {
 A -- B
 B -- C
}

Notice the difference: -> creates a directed edge, while -- creates an undirected one. This is one of the first syntax distinctions new users encounter, and mixing them up is a common source of errors.

How do you define and label nodes?

In its simplest form, a node is just an identifier:

MyNode

You assign attributes to nodes using square brackets. The most common attribute is label:

MyNode [label="My Custom Label"]

Other frequently used node attributes include:

  • shape box, ellipse, circle, diamond, plaintext, and many more
  • style filled, dashed, rounded, bold
  • fillcolor background fill color (requires style=filled)
  • color border/outline color
  • fontname font family for the label
  • width / height fixed dimensions in inches

A practical example:

Database [label="User DB", shape=cylinder, style=filled, fillcolor="#4A90D9", fontcolor=white]

You can set default attributes for all nodes at once by using the node keyword with attributes in brackets:

node [shape=box, style=filled, fillcolor=lightyellow]

Every node defined after that line inherits those defaults unless overridden individually.

How do edges work in DOT syntax?

Edges connect two nodes using an operator. In a digraph, use ->. In a graph, use --.

A -> B [label="connects to"]

Edges also accept attributes in square brackets:

  • label text displayed along the edge
  • color line color
  • style dashed, dotted, bold, solid
  • arrowhead none, normal, dot, diamond, crow, and others
  • arrowtail shape of the arrow at the tail end
  • dir direction: forward, back, both, none
  • weight influences edge length and layout priority

You can chain edges for compact notation:

A -> B -> C -> D

This is equivalent to writing three separate edge statements. If you're building more complex flows like those in architecture diagram examples, chaining keeps the code readable.

Can you set default edge attributes?

Yes. Just like nodes, edges have a global default keyword:

edge [color=gray, style=dashed, arrowhead=vee]

All edges defined after this line use those defaults unless you override them on a specific edge.

What about subgraphs and clusters?

Subgraphs group related nodes together. In Graphviz, if you name a subgraph with a prefix of cluster_, it renders as a visual box around those nodes.

digraph {
 subgraph cluster_frontend {
 label="Frontend"
 style=filled
 color=lightgrey
 
 UI -> API_Call
 }
 
 subgraph cluster_backend {
 label="Backend"
 style=filled
 color=lightblue
 
 Server -> Database
 }
 
 API_Call -> Server
}

Clusters are especially useful for system and network diagrams where you need to show boundaries between components or environments. This technique appears frequently when people automate reporting with Graphviz, since the layout engine handles positioning inside and outside clusters automatically.

How do you set the overall graph attributes?

Graph-level attributes control the entire diagram's appearance. Place them at the top of the graph body, outside any subgraph.

digraph {
 rankdir=LR
 bgcolor=white
 fontname="Arial"
 label="System Architecture"
 labelloc=t
 fontsize=18
 pad=0.5
 nodesep=0.8
 ranksep=1.0
}

Common graph attributes:

  • rankdir direction of layout: TB (top-bottom, default), LR (left-right), BT, RL
  • bgcolor background color of the entire canvas
  • label title displayed on the graph
  • labelloc vertical position of the label: t (top) or b (bottom)
  • nodesep minimum space between nodes in the same rank
  • ranksep minimum space between rank levels
  • splines edge routing style: ortho, curved, polyline, spline
  • concentrate merges edges that share endpoints (set to true)

What are HTML-like labels, and when should you use them?

DOT supports HTML-like label syntax when you need formatted text inside nodes things like bold, italic, line breaks, tables, or mixed formatting within a single label.

Info [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
 <TR><TD COLSPAN="2"><B>User Info</B></TD></TR>
 <TR><TD>Name</TD><TD>Jane Doe</TD></TR>
 <TR><TD>Role</TD><TD>Admin</TD></TR>
</TABLE>
>, shape=plaintext]

Use angle brackets < > instead of regular quotes to enable HTML label mode. This is useful for database schemas, structured data displays, and detailed component cards. Note that the syntax here is not full HTML it's a limited subset specific to Graphviz.

What common mistakes break DOT syntax?

Here are errors that trip up both beginners and experienced users:

  • Mixing directed and undirected operators. Using -> in a graph block or -- in a digraph block causes parsing errors.
  • Missing semicolons or braces. DOT is somewhat forgiving about whitespace and semicolons, but mismatched braces will fail silently or throw cryptic errors.
  • Using reserved words as node IDs. Words like node, edge, graph, subgraph, and strict are reserved. Wrap them in quotes if you need them as identifiers: "node" [label="Server"].
  • Forgetting to escape special characters. Characters like quotes, angle brackets, and backslashes inside labels need escaping: use \" for quotes inside a quoted string.
  • Confusing attribute separators. Attributes inside brackets are separated by commas, but you can also use whitespace. Consistency matters for readability.
  • Not specifying the graph type. If you start with just { instead of digraph {, the parser won't know which edge operator to expect.

How do you render a DOT file into an image?

From the command line, the basic syntax is:

dot -Tpng input.dot -o output.png

Supported output formats include -Tsvg, -Tpdf, -Tjpg, and -Tps. Different layout engines suit different graph types:

  • dot hierarchical/layered layouts (best for directed acyclic graphs)
  • neato spring model layouts (good for undirected graphs)
  • fdp force-directed placement
  • circo circular layout
  • twopi radial layout

If you don't have Graphviz installed locally, you can use an online DOT graph editor to write and preview your diagrams in the browser.

Quick reference: full DOT syntax example

Here's a complete, working example that combines the major syntax elements discussed above:

digraph Pipeline {
 rankdir=TB
 bgcolor=white
 fontname="Arial"
 node [shape=box, style="filled,rounded", fillcolor="#E8F4FD", fontname="Arial"]
 edge [color="#555555", fontname="Arial", fontsize=10]

 subgraph cluster_sources {
 label="Data Sources"
 style=filled
 color="#F0F0F0"
 
 CSV [label="CSV Files"]
 API [label="REST API"]
 }

 subgraph cluster_processing {
 label="Processing"
 style=filled
 color="#FFF3E0"
 
 ETL [label="ETL Pipeline", fillcolor="#FFB74D"]
 Validate [label="Validation", shape=diamond]
 }

 subgraph cluster_output {
 label="Output"
 style=filled
 color="#E8F5E9"
 
 DB [label="Warehouse", shape=cylinder]
 Report [label="Dashboard"]
 }

 CSV -> ETL
 API -> ETL
 ETL -> Validate
 Validate -> DB [label="pass"]
 Validate -> ETL [label="fail", style=dashed, color=red]
 DB -> Report
}

This example demonstrates directed edges, subgraph clusters, node and edge defaults, labels, shapes, colors, and feedback loops all in under 30 lines of plain text.

DOT language syntax cheat sheet

ElementSyntaxExample
Directed edgeA -> BStart -> End
Undirected edgeA -- BStart -- End
Node with attributesID [attr=value]Web [label="Web Server", shape=box]
Edge with attributesA -> B [attr=value]A -> B [label="data", style=dashed]
Default node attrsnode [attr=value]node [shape=ellipse]
Default edge attrsedge [attr=value]edge [color=gray]
Subgraphsubgraph name { ... }subgraph cluster_aws { ... }
Graph directionrankdir=LRLeft-to-right layout
HTML labellabel=<HTML>label=<<B>Bold</B>>
Comment// comment or / comment /Ignored by parser

Practical checklist before you render

  1. Start with digraph or graph pick the right one for your edge type.
  2. Define global defaults for node, edge, and graph-level attributes at the top.
  3. Use meaningful node IDs (they're internal identifiers; labels are what users see).
  4. Group related nodes inside subgraph cluster_ blocks for visual separation.
  5. Use rankdir=LR for wide diagrams, or keep the default TB for top-down flows.
  6. Test with dot -Tsvg first SVG output is resolution-independent and loads fast.
  7. Check for mismatched braces, missing operators, and reserved word conflicts if the output looks wrong.

Save this page as your go-to syntax reference, and when you're ready to build real diagrams, try experimenting with the architecture diagram DOT examples to see these rules applied in context.