If you've ever needed to create a flowchart, dependency diagram, or network topology map without dragging boxes around in a GUI, Graphviz and its DOT language are built for exactly that. The DOT language lets you describe graphs in plain text, and a tool called Graphviz turns those descriptions into visual diagrams. Having a solid understanding of the syntax from the start saves you hours of trial and error and that's what this reference is for.

What is the DOT language, and why use it?

DOT is a plain-text graph description language created by AT&T Labs. You write short, readable declarations that describe nodes (the boxes or circles) and edges (the lines connecting them). Graphviz then compiles that text into an image SVG, PNG, PDF, and more.

People use DOT because it works well for:

  • Flowcharts and decision trees
  • Software architecture and dependency diagrams
  • Network and infrastructure topology maps
  • State machines and finite automata
  • Database relationship diagrams

Unlike visual diagramming tools, DOT files are version-controllable, diffable, and reproducible. You describe what the graph contains, and the layout engine decides where things go.

How is a DOT file structured?

A DOT file has a simple structure. It starts with a graph type declaration, followed by attributes and node/edge definitions inside curly braces.

There are two graph types:

  • digraph a directed graph where edges have arrows showing direction
  • graph an undirected graph where edges are plain lines (uses -- instead of ->)

Here's the skeleton of a directed graph:

digraph {
  A -> B
  B -> C
}

This creates three nodes (A, B, C) with arrows from A to B and B to C. The layout engine positions them automatically.

How do you define nodes in DOT?

You don't need a separate declaration to create a node mentioning it in an edge creates it. But you can customize nodes by adding attributes after the node name.

A [label="Start", shape=box, style=filled, fillcolor=lightblue]

Common node attributes include:

  • label the text displayed inside the node
  • shape box, ellipse, circle, diamond, plaintext, hexagon, and many more
  • style filled, rounded, dashed, bold, or combinations like "filled,rounded"
  • fillcolor background color (requires style=filled)
  • color border color
  • fontname font family for the label text
  • width / height minimum size in inches

You can also set default node attributes that apply to every node in the graph:

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

Any node you define after this line will inherit those defaults unless you override them individually.

How do edges work in DOT syntax?

Edges connect nodes using -> for directed graphs or -- for undirected ones. You can chain them and add attributes the same way.

A -> B [label="depends on", color=red, style=dashed]

Common edge attributes include:

  • label text displayed along the edge
  • color line color
  • style solid, dashed, dotted, bold
  • arrowhead none, normal, open, diamond, vee, and others
  • weight affects how straight and short the edge is drawn (higher = straighter)
  • constraint set to false to let an edge not affect ranking

Default edge attributes work the same as node defaults:

edge [color=gray, fontsize=10]

How do you add comments and formatting?

DOT supports C++-style comments:

  • // single-line comment
  • / multi-line comment /
  • # single-line comment (shell-style, also works)

Whitespace and line breaks don't matter to the parser, so format your code for readability. Semicolons are optional but can be used to separate statements if you prefer.

What are subgraphs, and when should you use them?

Subgraphs group related nodes together. They're defined with the subgraph keyword and a name that must start with cluster_ if you want Graphviz to draw a bounding box around them.

subgraph cluster_auth {
  label="Authentication"
  style=dashed
  Login -> Validate
  Validate -> Token
}

Subgraphs are useful for logically grouping components in architecture diagrams or showing distinct modules. If the name doesn't start with cluster_, the grouping only affects layout, not visual appearance.

What is the difference between DOT graph attributes and node/edge attributes?

Graph-level attributes control the overall appearance and layout. You set them directly in the graph body without attaching them to a specific element.

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

Key graph attributes:

  • rankdir TB (top to bottom, default), LR (left to right), BT, RL
  • bgcolor background color of the entire canvas
  • label title text for the graph
  • nodesep minimum space between nodes (in inches)
  • ranksep minimum space between ranks/levels
  • dpi resolution for raster output
  • overlap controls how overlapping nodes are handled

What is ranking, and how does it control layout?

Ranking determines which nodes appear on the same horizontal or vertical level. DOT uses rank statements for this:

  • same forces listed nodes onto the same level
  • min puts nodes at the top (or start)
  • max puts nodes at the bottom (or end)
  • source like min, but also affects connected nodes
  • sink like max, but also affects connected nodes

Example:

{rank=same; B; C; D}

This forces nodes B, C, and D to appear at the same vertical level. If you want to go further with rank-based grouping and visual styling, check out the advanced node styling and ranking attributes reference.

What are the most common mistakes beginners make?

  1. Mixing up -> and --. Use -> for digraphs and -- for undirected graphs. Using the wrong one causes a syntax error.
  2. Forgetting that node IDs are case-sensitive. A and a are two different nodes.
  3. Using special characters in labels without quotes. If your label has spaces, colons, or HTML characters, wrap it in double quotes.
  4. Not quoting attribute values with special characters. label=My Label breaks. Use label="My Label".
  5. Placing attributes in the wrong position. Attributes go inside square brackets after the element they apply to, or in a default statement.
  6. Expecting exact pixel placement. DOT is a declarative language the layout engine makes positioning decisions. If you need precise control, you may need to switch to a different layout engine like neato or fdp.

How do you render a DOT file?

Once you've written your DOT code, you can render it with the dot command-line tool:

dot -Tpng graph.dot -o graph.png

Common output formats (-T flag):

  • png raster image
  • svg scalable vector image (best for web)
  • pdf printable document
  • jpg compressed raster image

If you don't want to install Graphviz locally, you can test and preview your code instantly using an online DOT editor with live rendering.

What does a complete beginner example look like?

Here's a simple project dependency graph that puts several concepts together:

digraph project {
  rankdir=TB
  fontname="Helvetica"
  node [shape=box, style="filled,rounded", fillcolor="#e8f4f8"]
  edge [color=gray, arrowhead=vee]

  subgraph cluster_frontend {
    label="Frontend"
    style=dashed
    HTML -> CSS
    HTML -> JS [label="interactivity"]
  }

  subgraph cluster_backend {
    label="Backend"
    style=dashed
    API -> Database
  }

  JS -> API [label="requests", style=dashed, color=blue]
}

This creates two grouped sections (Frontend and Backend) with labeled, styled edges showing how they connect.

Quick reference: DOT syntax cheat sheet

  • Directed edge: A -> B
  • Undirected edge: A -- B
  • Node attributes: A [label="Name", shape=box]
  • Edge attributes: A -> B [label="text", color=red]
  • Graph attributes: rankdir=LR
  • Defaults: node [shape=ellipse] or edge [style=dashed]
  • Subgraph: subgraph cluster_name { ... }
  • Rank: {rank=same; X; Y; Z}
  • Render: dot -Tsvg file.dot -o file.svg

Keep this page bookmarked. When you're ready to move beyond the basics, the advanced styling and ranking guide covers HTML-like labels, complex color schemes, and fine-grained layout control.

Beginner's next-step checklist

  1. Install Graphviz on your machine or open a live DOT editor to start testing immediately.
  2. Write a simple 3-node digraph with A -> B -> C and render it to SVG.
  3. Add labels and change one node's shape to diamond.
  4. Group related nodes into a subgraph cluster_ and observe the visual difference.
  5. Change rankdir from TB to LR and see how the layout shifts.
  6. Try the dot, neato, and fdp engines on the same file to compare layout styles.

Start small, break things, and read the error messages they're usually clear about what syntax you got wrong.