Become a member!

Practical Guide to DOT Language (Graphviz) for Developers and Analysts

For developers, analysts and software architects who want to produce professional diagrams that are clear and beautiful to look at

  • ๐Ÿ‡ฎ๐Ÿ‡น Questo articolo รจ disponibile anche in italiano.
  • ๐Ÿ‡ช๐Ÿ‡ธ Este artรญculo tambiรฉn estรก disponible en espaรฑol.

Introduction

In the daily work of software developers โ€” whether you’re an analyst, backend developer, frontend developer, database expert or architect โ€” there always comes a time when a diagram becomes essential.

You need it when you have to:

  • explain a complex flow,
  • draw the CI/CD pipeline,
  • describe the architecture to a new colleague,
  • analyze dependencies between modules,
  • document a database,
  • prepare a technical presentation,
  • reason about a refactoring,
  • identify bottlenecks.

Graphviz and its DOT language are ideal tools: textual (versionable), fast to write, beautiful to render, flexible.

Installing Graphviz

Before starting, make sure you have Graphviz installed:

  • Windows: Download the installer from graphviz.org/download or use winget install graphviz
  • macOS: brew install graphviz
  • Linux: sudo apt install graphviz (Debian/Ubuntu) or sudo dnf install graphviz (Fedora/RHEL)

Verify the installation with dot -V โ€” you should see the installed version.

This manual aims to be the definitive guide for those in software who want to use the DOT language to its fullest. You’ll find:

  • in-depth explanation of attributes with all relevant options,
  • complete, reusable and commented examples,
  • best practices for professional graphics,
  • suggestions on using layout engines,
  • concrete scenarios from the development world (design, refactoring, analysis, architecture).

The DOT language: solid foundations

DOT describes graphs with a very simple syntax:

digraph Name {
    nodeA -> nodeB;
}

Or undirected:

graph Name {
    nodeA -- nodeB;
}

Key concepts:

  • nodes: entities (functions, objects, microservices, DB tables)
  • edges: relationships, calls, flows
  • attributes: visual appearance or metadata

Quick Start: your first diagram in 30 seconds

Test immediately online (without installing anything)

All examples in this article can be tested directly online using Edotor.net:

  1. Go to edotor.net

  2. Copy the DOT code from any example in this article

  3. Paste it in the left area (replacing the existing code)

  4. See the immediate rendering in the right area

It’s the fastest way to experiment without installing Graphviz. When you’re ready for production, install Graphviz locally.

First example to try

Copy this code and test it on edotor.net:

digraph MyFirstGraph {
    node [shape=box, style=rounded, fillcolor=lightblue, style="rounded,filled"];
    edge [color=blue];

    Start -> Process -> End;
    Process -> Error [style=dashed, label="on failure"];
    Error -> Process [label="retry"];
}

Or use the local command line

Create a hello.dot file with the code above and generate the SVG image:

dot -Tsvg hello.dot -o hello.svg

Open hello.svg in your browser and you’ll see your first flowchart! From here on, everything is based on variations and combinations of these concepts.


Fundamental attributes (with complete options)

Attributes can be applied globally to:

  • graph
  • node
  • edge
  • individual elements

Example:

digraph demo {
    graph [rankdir=LR];
    node [shape=box];
    edge [color=grey];

    A -> B;
}

Below is a list of the most important attributes with their most useful options in software development.


Node attributes (node)

shape โ€” node shape

Useful options:

  • box
  • ellipse
  • circle
  • diamond (decisions in flows)
  • record (class diagrams, data structures)
  • plaintext (fully customized content with HTML-label)
  • note
  • folder (available in some builds)

Example:

node [shape=box];

Typical uses:

  • box โ†’ software modules
  • ellipse โ†’ states
  • diamond โ†’ decisions

style โ€” graphic style

Common options:

  • filled
  • dashed
  • dotted
  • bold
  • rounded
  • combinations: "filled,rounded"

Example:

node [style="filled,rounded"];

fillcolor โ€” fill color

Formats:

  • names (e.g. "lightgrey")
  • HEX (e.g. "#AABBCC")
  • RGB ("#rrggbb")
  • HSL (in some builds)

fontname, fontcolor, fontsize

E.g.:

node [fontname="Arial", fontsize=12, fontcolor="#333333"];

margin

Internal margin of the node.

node [margin="0.2,0.1"];

Edge attributes (edge)

arrowsize

Arrow scale. Default ~1.0

edge [arrowsize=0.8];

arrowhead / arrowtail

Useful options:

  • normal
  • empty (hollow triangle, very readable)
  • diamond
  • onormal
  • crow (ER diagrams)
  • tee
  • none

style and color

edge [style=dashed, color="#888888"];

label

Edge label.

A -> B [label="calls"];

Graph attributes (graph)

rankdir

Layout direction (only dot):

  • TB (top โ†’ bottom)
  • BT (bottom โ†’ top)
  • LR (left โ†’ right)
  • RL (right โ†’ left)

E.g.:

graph [rankdir=LR];

splines

Controls the shape of edges:

  • true (default)
  • false (straight lines)
  • polyline
  • ortho (orthogonal, great for “architect” diagrams)

ranksep, nodesep

Horizontal/vertical spacing.

graph [ranksep=0.8, nodesep=0.6];

Layout Engines: choosing the right one

Graphviz doesn’t have just one rendering engine: it offers several, each optimized for specific types of graphs. Choosing the right engine means getting more readable and professional diagrams.

You specify the engine using the -K flag from CLI:

dot -Kdot -Tsvg file.dot -o output.svg
dot -Kneato -Tsvg file.dot -o output.svg

Or in the DOT file itself:

graph G {
    layout=neato;
    // ...
}

Below are the main engines and when to use them.


Available layout engines

dot โ€” hierarchical layout (default)

What it does: Arranges nodes hierarchically, following the direction of edges. It’s the most used.

Perfect for:

  • Flowcharts and flow diagrams
  • CI/CD pipelines
  • Call graphs (graph of calls between functions)
  • Layered architectures (presentation โ†’ business โ†’ data)
  • Sequential processes
  • Dependency diagrams with clear direction

Example command:

dot -Tsvg flowchart.dot -o flowchart.svg

When to avoid it: If the graph doesn’t have a clear hierarchical structure or contains many cycles.

neato โ€” force-directed layout

What it does: Positions nodes by simulating physical forces (repulsion/attraction), generating organic and symmetric layouts.

Useful for:

  • Undirected graphs (without arrows)
  • Conceptual networks and mind maps
  • Non-hierarchical relationships between entities
  • Small/medium graphs where you want to highlight natural clusters

Example command:

dot -Kneato -Tsvg concepts.dot -o concepts.svg

When to avoid it: With very large graphs (>100 nodes) or highly directional ones.

fdp โ€” force-directed placement

What it does: Similar to neato, but uses a different algorithm (Fruchterman-Reingold). Generally faster on medium graphs.

Useful for:

  • Medium-sized undirected graphs
  • Social network visualizations (friendships, connections)
  • Dependency analysis without strong direction

Example command:

dot -Kfdp -Tsvg network.dot -o network.svg

sfdp โ€” scalable force-directed placement

What it does: Optimized version of fdp for very large graphs (thousands of nodes).

Great for:

  • Dependency analysis on complex codebases
  • Class graph of an enterprise project
  • Complex networks (infrastructure, microservices)
  • When neato or fdp are too slow

Example command:

dot -Ksfdp -Tsvg dependencies.dot -o dependencies.svg

Tip: Use sfdp when you have more than 100-200 nodes.

circo โ€” circular layout

What it does: Arranges nodes in concentric circles around a central node.

Ideal for:

  • Visualizing satellite modules around a central core
  • Hub-and-spoke architectures
  • Representing components that depend on a central service

Example command:

dot -Kcirco -Tsvg modules.dot -o modules.svg

Practical example: A central API service with 10 microservices calling it.

twopi โ€” radial layout

What it does: Creates a radial tree layout, with the root node at the center and levels expanding outward.

Perfect for:

  • Hierarchical trees (org chart, file system)
  • Taxonomies
  • Structured mind maps
  • Visualizing expansions from a central point

Example command:

dot -Ktwopi -Tsvg tree.dot -o tree.svg

How to choose in practice

Graph type Recommended engine
Flowchart, pipeline, processes dot
Layered architectures dot
Call graph, dependency tree dot
Conceptual network, brainstorming neato
Social network, medium undirected graphs fdp
Large graphs (>200 nodes) sfdp
Central hub with satellites circo
Hierarchical trees, org chart twopi

Practical rule: If you have arrows and a clear direction โ†’ use dot. Otherwise try neato or fdp.


Types of diagrams and when to use them in a developer’s real life

This is the most substantial section. For each type of diagram you’ll find:

  • When to use it in real life
  • Recommended attributes
  • Complete example

Flowchart: understanding behavior

In daily work it often happens that you need to explain a complex decision flow: a validation procedure with multiple branches, a user onboarding process, or simply the behavior of a function with many nested if/else. The flowchart is the ideal tool for this.

When you need a flowchart:

You’re in the requirements analysis phase and need to understand all possible cases. You’re debugging logic that seems to have gone crazy and want to see visually where the flow branches. You need to write documentation for a complex business process. You’re onboarding a new colleague and want to show them how the authentication system works.

The flowchart visually shows decisions (diamonds), processes (rounded rectangles), and logical flow (arrows). It’s immediate, clear, universal.

Recommended attributes for professional flowcharts:

Use rankdir=TB (top-to-bottom) to follow the standard flowchart convention. Use shape=diamond for decision nodes (if/else conditions). Use style=rounded for process steps, so they stand out from diamonds. Use soft colors (fillcolor) to highlight start (light green), errors (light red), end (gray).

Complete example:

digraph Flow {
    graph [rankdir=TB, nodesep=0.6];
    node [fontname="Arial"];

    Start   [shape=oval, style=filled, fillcolor="#C1F2C7"];
    Check   [shape=diamond, label="Valid input?"];
    Process [shape=box, style="filled,rounded", fillcolor="#F0F4FF"];
    Error   [shape=box, fillcolor="#FFEAEA", style=filled];
    End     [shape=oval, fillcolor="#DDDDDD", style=filled];

    Start -> Check;
    Check -> Process [label="yes"];
    Check -> Error   [label="no"];
    Process -> End;
}

What this example does: Starts from an initial state (Start), goes through validation (Check), and branches into two paths: success (Process) or error (Error). Uses colors to make it immediately clear what is positive and what is negative.


Dependency graphs: understanding software as a system

When working on an existing project, one of the first questions you ask yourself is: “What depends on what?” If you need to refactor a module, you want to know who uses it. If you need to update a library, you want to understand the cascading impact. If you’re designing a new feature, you want to see where it fits in the existing architecture.

The dependency graph is the map of your system. It shows modules, services, classes, or microservices as nodes, and dependencies as arrows. It’s essential for:

Safe refactoring: Before touching a module, see who calls it. Impact analysis: If you modify an API, you immediately see all consumers. Automatic documentation: Generate the graph from code (with tools like Doxygen, Madge, or custom scripts) and keep it updated. Dependency injection mapping: Visualize how Spring, Angular or .NET inject dependencies.

Useful attributes:

Use rankdir=LR (left-to-right) to have a horizontal flow, typical of dependency chains. Use shape=box for modules/services. Use color and penwidth to highlight critical or problematic dependencies (e.g. circular dependencies in red). Use style=dashed for optional or weak dependencies.

Example:

digraph Deps {
    graph [rankdir=LR];
    node [shape=box, style=filled, fillcolor="#F7FAFF", fontname="Inter"];
    edge [color="#555555"];

    UI -> API;
    API -> Auth;
    API -> UserService;
    UserService -> Database [color="#FF5555", penwidth=2, label="critical"];
}

What this example does: Shows a classic web architecture: UI calls API, API depends on Auth and UserService, UserService talks to Database. The critical dependency (UserService โ†’ Database) is highlighted in red with thick line: if the DB goes down, everything collapses.


Software architecture: clusters and layers

When you design an architecture or document the existing one, you need to show logical groupings and layer separation. A typical web system has Presentation, Business, Data. A microservices project has logical boundaries (edge, services, datastores). A legacy system might have modules separated by domain.

The architecture diagram with clusters allows you to:

Visualize separate layers: Presentation Layer, Business Layer, Data Layer. Each layer is a colored box containing its components. Show microservice boundaries: Edge Gateway, Services, Datastores. Each boundary is a cluster. Document legacy modules: Isolate modules by responsibility (Auth, Orders, Reporting) so it’s clear who does what. Present architecture to stakeholders: A layered diagram is universal and understandable even by non-technical people.

Useful attributes:

Use subgraph cluster_* to create visual groupings. Use compound=true to allow edges that cross clusters. Use splines=ortho for orthogonal lines, typical of “architect” diagrams. Use shape=cylinder for databases, so they’re immediately recognizable.

Layered architecture example:

digraph Architecture {
    graph [
        rankdir=TB,
        ranksep=0.8,
        nodesep=0.6,
        overlap=false,
        splines=true,
        sep="+0.2"
    ];
    node [shape=box, style="rounded,filled", fillcolor="#F0F4FF", fontname="Arial"];

    subgraph cluster_presentation {
        label="Presentation Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#E8F4F8";
        UI;
    }

    subgraph cluster_business {
        label="Business Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#FFF4E6";
        ServiceA; ServiceB;
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#F0F0F0";
        DB [shape=cylinder, fillcolor="#D0E8FF"];
    }

    UI -> ServiceA;
    UI -> ServiceB;
    ServiceA -> DB;
    ServiceB -> DB;
}

What this example does: Defines three layers with subgraph cluster_*. Presentation contains UI, Business contains two services, Data contains DB (with shape=cylinder). Arrows show the flow: UI โ†’ Services โ†’ DB. The architecture is immediately understandable.


Microservices Map: understanding a distributed ecosystem

If you work with microservices, you have dozens of services communicating with each other: API Gateway, domain services (Orders, Users, Notifications), databases, queues, caches. When a production incident occurs, the first question is: “Who talks to whom? Where’s the bottleneck?”

The microservices map is your GPS in distributed chaos. You need it for:

Architectural design: Before writing code, draw the map. Identify logical boundaries (edge, core services, datastores). API documentation: Show who calls which service and through which protocol (REST, gRPC, events). Performance analysis: During an incident, you look at the map and immediately understand if the problem is in the API Gateway, in a specific service, or in the shared DB. Post-mortem: After downtime, the map helps reconstruct the failure chain.

Useful attributes:

Use cluster to separate logical boundaries (Edge, Services, Data). Use shape=cylinder for databases, shape=box for services. Use labels on edges to specify protocol (HTTP, gRPC, Kafka). Use shape=plaintext with HTML table for complex services with multiple ports.

Example:

digraph Micro {
    graph [rankdir=LR, splines=true];
    node [shape=plaintext];

    subgraph cluster_gateway {
        label="Edge";
        Gateway [label="API Gateway"];
    }

    subgraph cluster_services {
        label="Services";
        Order; User; Notification;
    }

    subgraph cluster_data {
        label="Datastores";
        DB [shape=cylinder, label="Postgres"];
        Cache [shape=box, label="Redis"];
    }

    Gateway -> User;
    Gateway -> Order;
    Order -> DB;
    User -> Cache;
    Notification -> User;
}

What this example does: Organizes the ecosystem into three clusters: Edge (Gateway), Services (Order, User, Notification), Datastores (DB, Cache). Arrows show the calls: Gateway โ†’ User/Order, Order โ†’ DB, User โ†’ Cache. It’s the complete map of the system.


State diagrams: modeling behaviors

Many systems have state-based behavior: an HTTP request can be Idle, Loading, Success, Error. An e-commerce order goes from Draft โ†’ Pending โ†’ Confirmed โ†’ Shipped. An embedded system has power-on, standby, operational, error states. A UI interface has loading, ready, error states.

The state diagram models these behaviors as a graph: each node is a state, each edge is a transition labeled with the event that causes it. It’s essential for:

Designing state machines: Before implementing the state pattern in code, draw the diagram. Documenting protocols: Network protocols (TCP, WebSocket, custom) have precise state machines. The diagram makes them explicit. Modeling UI/UX flow: When designing an app, draw the interface states: loading, ready, error, empty. Debugging embedded systems: If a device gets stuck in a state, the diagram helps you understand which transitions are missing.

Useful attributes:

Use shape=circle for states (standard FSM convention). Use rankdir=LR for horizontal layout, typical of state diagrams. Use label on edges to show the event causing the transition. Use shape=doublecircle for final/terminal states.

Example:

digraph States {
    graph [rankdir=LR];
    node [shape=circle, fontsize=12];

    Idle -> Loading   [label="start"];
    Loading -> Ready  [label="success"];
    Loading -> Error  [label="fail"];
    Error -> Idle     [label="reset"];
    Ready -> Idle     [label="finish"];
}

What this example does: Models the lifecycle of an asynchronous request: starts from Idle, goes to Loading when the call starts, then Success or Error depending on the result. From Error it can return to Idle with a reset. From Ready it can return to Idle on completion. Each transition is labeled with the event that causes it.


Class diagrams with record

When you design an object-oriented system, or want to document an application’s domain, the class diagram is the standard. It shows classes with attributes and methods, and relationships between them (inheritance, composition, dependency).

DOT is not UML, but with shape=record you get something very similar and perfectly readable. It’s useful for:

Initial design: Before writing code, draw the main domain classes. Identify attributes, methods, relationships. Refactoring: When you need to restructure a module, draw the current state and the desired one. Compare the two diagrams. Domain-Driven Design (DDD): Model entities, value objects, aggregates. The diagram helps visualize domain boundaries. Documentation: Generate the diagram automatically from code (with tools like Doxygen) and keep it updated.

Useful attributes:

Use shape=record to create boxes with separate sections (class name | attributes | methods). Use fontname="Courier New" or monospace to make it look like code. Use arrowhead=onormal for inheritance (hollow arrow, UML standard). Use \l (backslash-l) to left-align text inside records.

Example:

digraph Classes {
    node [shape=record, fontname="Courier New"];

    Person [label="{Person|name: string\l age: int\l|greet()}"];
    Employee [label="{Employee|id: int\l role: string\l|work()}"];

    Person -> Employee [arrowhead="onormal"];
}

What this example does: Defines two classes: Person (with attributes name, age, method greet) and Employee (with id, role, method work). Person is the superclass of Employee (arrow with arrowhead=onormal, UML standard for inheritance). The \l left-aligns text inside records.


Professional ER diagrams with HTML-label

If you work with databases, sooner or later you need to draw the table schema: primary keys, foreign keys, 1:N or N:N relationships. The Entity-Relationship (ER) diagram is the standard for this.

DOT supports HTML tables inside nodes with shape=plaintext, allowing you to create clean and professional ER diagrams. It’s essential for:

Database design: Before writing migrations, draw the schema. Identify entities, attributes, relationships. Validate the design with the team. Data modeling: When designing a new module, start with the data model. The ER diagram helps you reason about normalization and performance. Reverse engineering: When you inherit a legacy DB without documentation, generate the ER diagram from the DB itself (with tools like SchemaSpy or pg_dump + script) to understand the structure. Documentation: The ER diagram is understandable even by non-developers (product managers, business analysts).

Useful attributes:

Use shape=plaintext to enable HTML label. Use HTML <TABLE> to create structured boxes with header (table name) and rows (fields). Use arrowhead=crow for 1:N relationships (ER diagram standard). Use label="1:N" on edges to make cardinality explicit.

Example:

digraph ER {
    node [shape=plaintext];

    User [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
            <TR><TD><B>User</B></TD></TR>
            <TR><TD>id PK</TD></TR>
            <TR><TD>email</TD></TR>
        </TABLE>
    >];

    Order [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
            <TR><TD><B>Order</B></TD></TR>
            <TR><TD>id PK</TD></TR>
            <TR><TD>user_id FK</TD></TR>
        </TABLE>
    >];

    User -> Order [label="1:N", arrowhead="crow"];
}

What this example does: Defines two tables (User and Order) using HTML. Each table has a bold header and rows for fields. The arrow with arrowhead=crow and label="1:N" shows the relationship: one User has many Orders (foreign key user_id in Order).


CI/CD Pipeline diagrams

If you work in a team doing continuous integration and deployment, you have a pipeline that executes automatic steps: build, test, static analysis, packaging, deploy, monitoring. When something breaks, or when you onboard a new developer, you need a diagram showing the entire pipeline.

The CI/CD diagram visualizes the automatic flow from commit to deploy. It’s useful for:

DevOps and SRE: Document the existing pipeline. Identify bottlenecks (which step takes the most time?). Team onboarding: A new developer looks at the diagram and immediately understands what happens after a git push. Optimization: Want to parallelize some steps? The diagram shows you which depend on which. Debugging: Pipeline failing? The diagram helps you understand at which step and why (dashed arrow for retries).

Useful attributes:

Use rankdir=LR for horizontal flow (typical of pipelines). Use shape=box with style=filled for steps, coloring them by type (build=blue, test=green, deploy=red). Use style=dotted with label="retry" to show automatic retry mechanisms. Use label on edges to indicate conditions (e.g. “only on master branch”).

Example:

digraph CICD {
    graph [rankdir=LR];
    node [shape=box, style=filled, fillcolor="#F8FBFF"];

    Code -> Build -> Test -> Package -> Deploy -> Monitor;

    Test -> Build [style=dotted, label="retry"];
}

What this example does: Shows a classic pipeline: Code โ†’ Build โ†’ Test โ†’ Package โ†’ Deploy โ†’ Monitor. The dashed arrow from Test to Build shows an automatic retry in case of test failure. It’s a linear flow, immediately understandable.


Reducing complexity: conceptual maps and analysis

Not all diagrams need to be hierarchical or directional. Sometimes you need to visualize conceptual relationships without a fixed structure: during brainstorming, when doing collective design with the team, or when you want to map conceptual dependencies between technological areas.

The conceptual map doesn’t have a “start” or “end”: it’s a network of organically connected nodes. It’s useful for:

Brainstorming: Start from a central idea and add connected nodes while discussing with the team. The map grows naturally. Collective design: During a design session, map components and their relationships. You don’t know the hierarchy yet, but you know “Backend talks to Database and API”. Conceptual dependency analysis: You want to understand which technological areas are connected (e.g. Security โ†’ Logging โ†’ Observability). High-level documentation: For non-technical stakeholders, a conceptual map is more accessible than a hierarchical graph.

Useful attributes:

Use neato or fdp engine instead of dot, to get an organic layout based on physical forces. Use shape=ellipse for conceptual nodes (not processes). Use style=filled with soft colors for visual groupings. Use undirected graphs (graph instead of digraph) if relationships are bidirectional.

Example with neato engine:

graph Concepts {
    layout=neato;
    node [shape=ellipse, style=filled, fillcolor="#EFEFFF"];

    Backend -- Database;
    Backend -- API;
    API -- Security;
    Security -- Logging;
    Logging -- Observability;
}

Avoiding overlaps: overlap and splines

One of the most common problems when drawing complex graphs is overlapping arrows, text and nodes. Graphviz offers specific attributes to control this behavior and make diagrams more readable.

The problem: unwanted overlaps

When you have many nodes and arrows, especially with hierarchical layouts or with splines=ortho, arrows can overlap cluster labels or nodes. Here’s a typical example of the problem:

digraph OverlapProblem {
    graph [rankdir=TB, splines=ortho];
    node [shape=box, style=rounded];

    subgraph cluster_a {
        label="Component A";
        A1; A2;
    }

    subgraph cluster_b {
        label="Component B";
        B1; B2;
    }

    subgraph cluster_c {
        label="Component C";
        C1; C2;
    }

    A1 -> B1;
    A2 -> B2;
    B1 -> C1;
    B2 -> C2;
    A1 -> C1;
}

Problem: With splines=ortho arrows can cross cluster labels making the diagram confusing.

The solution: overlap and splines

Graphviz offers several attributes to solve this problem:

overlap โ€” avoid overlaps between nodes

graph [overlap=false];

Main options:

  • false or voronoi โ€” avoid overlaps (better quality, slower)
  • scale โ€” scale the graph to avoid overlaps
  • scalexy โ€” scale with different proportions on X and Y
  • true (default) โ€” allow overlaps

splines โ€” control edge shape

graph [splines=true];

Options:

  • true or spline โ€” smooth curves that avoid nodes (recommended)
  • curved โ€” slightly curved edges
  • polyline โ€” broken lines
  • ortho โ€” orthogonal lines (can cause overlaps!)
  • line or false โ€” straight lines

sep โ€” extra margin between elements

graph [sep="+0.2"];

Adds margin between nodes and edges (in inches). The + means “add to default value”.

ranksep and nodesep โ€” spacing between levels and nodes

graph [ranksep=0.8, nodesep=0.6];

Increases vertical (ranksep) and horizontal (nodesep) space between elements.

Improved example

Here’s the same graph with optimized attributes to avoid overlaps:

digraph OverlapSolved {
    graph [
        rankdir=TB,
        ranksep=0.8,
        nodesep=0.6,
        overlap=false,
        splines=true,
        sep="+0.2"
    ];
    node [shape=box, style=rounded];

    subgraph cluster_a {
        label="Component A";
        style=filled;
        fillcolor="#E8F4F8";
        A1; A2;
    }

    subgraph cluster_b {
        label="Component B";
        style=filled;
        fillcolor="#FFF4E6";
        B1; B2;
    }

    subgraph cluster_c {
        label="Component C";
        style=filled;
        fillcolor="#F0F0F0";
        C1; C2;
    }

    A1 -> B1;
    A2 -> B2;
    B1 -> C1;
    B2 -> C2;
    A1 -> C1;
}

Result: Arrows now avoid nodes and labels, the graph is more spacious and readable. Background colors help distinguish clusters.

When to use what

Scenario Recommended attributes
Complex diagrams with many nodes overlap=false, splines=true
Hierarchical graphs (flowcharts, architectures) ranksep=0.8, nodesep=0.6, splines=true
Graphs with clusters overlap=false, sep="+0.2"
“Architect” diagrams with straight lines splines=polyline (avoid ortho)
Small and simple graphs default (no need to modify)

Practical rule: Always start with overlap=false and splines=true if you have more than 10 nodes or use clusters.

Complete example with all best practices

Here’s a real example combining all recommended attributes: microservices architecture with 4 layers, many nodes and edges, colored clusters, optimized spacing:

digraph CompleteExample {
    graph [
        rankdir=TB,
        ranksep=1.0,
        nodesep=0.7,
        overlap=false,
        splines=true,
        sep="+0.25"
    ];
    node [shape=box, style="rounded,filled", fillcolor="#F0F4FF", fontname="Arial", fontsize=11];
    edge [color="#555555", arrowsize=0.8];

    subgraph cluster_frontend {
        label="Frontend Layer";
        style=filled;
        fillcolor="#E8F4F8";
        color="#5A9FD4";

        WebUI [label="Web UI"];
        MobileApp [label="Mobile App"];
    }

    subgraph cluster_api {
        label="API Gateway Layer";
        style=filled;
        fillcolor="#FFF4E6";
        color="#E8A87C";

        Gateway [label="API Gateway"];
        LoadBalancer [label="Load Balancer"];
    }

    subgraph cluster_services {
        label="Microservices Layer";
        style=filled;
        fillcolor="#F0F8E8";
        color="#90C290";

        AuthService [label="Auth Service"];
        UserService [label="User Service"];
        OrderService [label="Order Service"];
        PaymentService [label="Payment Service"];
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        fillcolor="#F5F5F5";
        color="#999999";

        UsersDB [shape=cylinder, fillcolor="#D0E8FF", label="Users DB"];
        OrdersDB [shape=cylinder, fillcolor="#D0E8FF", label="Orders DB"];
        Cache [shape=box, fillcolor="#FFE8D0", label="Redis Cache"];
    }

    // Frontend to Gateway
    WebUI -> LoadBalancer [label="HTTPS"];
    MobileApp -> LoadBalancer [label="HTTPS"];

    // Gateway to Services
    LoadBalancer -> Gateway;
    Gateway -> AuthService [label="gRPC"];
    Gateway -> UserService [label="REST"];
    Gateway -> OrderService [label="REST"];

    // Service dependencies
    OrderService -> PaymentService [label="API call"];
    UserService -> AuthService [label="validate"];
    PaymentService -> AuthService [label="validate"];

    // Data access
    AuthService -> UsersDB;
    UserService -> UsersDB;
    UserService -> Cache [style=dashed, label="cache"];
    OrderService -> OrdersDB;
    OrderService -> Cache [style=dashed, label="cache"];
}

Command line:

dot -Tsvg overlap_complete.dot -o overlap_complete.svg

What this example demonstrates:

  • overlap=false: No overlaps between nodes, even with 13 nodes and 4 clusters
  • splines=true: Curved arrows that elegantly avoid nodes and labels
  • sep="+0.25": Extra margin that keeps everything readable
  • ranksep=1.0, nodesep=0.7: Generous spacing between layers and nodes
  • Colored clusters: Each layer has a distinctive color for immediate identification
  • Labels on edges: Protocols (HTTPS, gRPC, REST) and connection type explicit
  • Dashed style for cache: Optional dependencies visualized differently
  • Cylinder shape for DB: Databases immediately recognizable

This is the perfect template for documenting complex architectures in a professional and readable way.


Color Schemes: professional ready-to-use palettes

Graphviz includes predefined color schemes based on professional palettes from ColorBrewer. Instead of choosing colors manually, you can use palettes tested for readability, accessibility and professionalism.

How color schemes work

Use the colorscheme attribute to select a palette, then use numbers 1-9 (or more, depends on the scheme) instead of hex codes:

node [colorscheme=set39, fillcolor=1, color=2];

Color schemes are organized into categories:

  • Qualitative (set1, set2, set3, pastel1, pastel2, dark2, paired, accent) โ€” For distinct categories
  • Sequential (blues3-9, greens3-9, reds3-9, purples3-9, oranges3-9) โ€” For progressive values
  • Diverging (rdylgn3-11, spectral3-11, rdbu3-11) โ€” For data with central point

Complete reference: graphviz.org/docs/attrs/colorscheme/

Practical examples with professional color schemes

Each example uses the same diagram (5-step process) but with different palettes. Compare and choose the one most suitable for your use case.

Example 1: Set39 (qualitative, vibrant)

Great for distinguishing different categories, colored presentations, dashboards.

digraph ProcessSet39 {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=set39, fontname=Arial];
    edge [colorscheme=set39, penwidth=2];

    Start [fillcolor=1, label="Start"];
    Validate [fillcolor=2, label="Validate"];
    Process [fillcolor=3, label="Process"];
    Store [fillcolor=4, label="Store"];
    Notify [fillcolor=5, label="Notify"];

    Start -> Validate [color=1];
    Validate -> Process [color=2];
    Process -> Store [color=3];
    Store -> Notify [color=4];
}

Command line:

dot -Tsvg colorscheme_set39.dot -o colorscheme_set39.svg

Example 2: Pastel19 (qualitative, soft)

Pastel colors for technical documentation, wikis, blog posts. Less impactful but more readable long-term.

digraph ProcessPastel {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=pastel19, fontname=Arial, fontcolor="#333333"];
    edge [colorscheme=dark28, penwidth=2];

    Start [fillcolor=1, label="Start"];
    Validate [fillcolor=3, label="Validate"];
    Process [fillcolor=5, label="Process"];
    Store [fillcolor=7, label="Store"];
    Notify [fillcolor=9, label="Notify"];

    Start -> Validate [color=1];
    Validate -> Process [color=3];
    Process -> Store [color=5];
    Store -> Notify [color=7];
}

Command line:

dot -Tsvg colorscheme_pastel.dot -o colorscheme_pastel.svg

Example 3: Blues9 (sequential, progression)

Ideal for showing increasing intensity, priorities, maturation phases.

digraph ProcessBlues {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=blues9, fontname=Arial];
    edge [color="#2171B5", penwidth=2];

    Start [fillcolor=2, fontcolor=black, label="Start"];
    Validate [fillcolor=4, fontcolor=white, label="Validate"];
    Process [fillcolor=6, fontcolor=white, label="Process"];
    Store [fillcolor=8, fontcolor=white, label="Store"];
    Notify [fillcolor=9, fontcolor=white, label="Notify"];

    Start -> Validate -> Process -> Store -> Notify;
}

Command line:

dot -Tsvg colorscheme_blues.dot -o colorscheme_blues.svg

Example 4: RdYlGn9 (diverging, traffic light)

Perfect for success/warning/error states, health checks, monitoring.

digraph ProcessStatus {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=rdylgn9, fontname=Arial, fontcolor=black];
    edge [penwidth=2, color="#666666"];

    Idle [fillcolor=5, label="Idle\n(neutral)"];
    Starting [fillcolor=7, label="Starting\n(ok)"];
    Running [fillcolor=9, label="Running\n(good)"];
    Warning [fillcolor=4, label="Warning"];
    Error [fillcolor=1, label="Error"];

    Idle -> Starting -> Running;
    Running -> Warning [style=dashed];
    Warning -> Error [style=dashed];
    Running -> Idle [label="stop"];
}

Command line:

dot -Tsvg colorscheme_rdylgn.dot -o colorscheme_rdylgn.svg

Example 5: Paired12 (qualitative, pairs)

Uses coordinated color pairs. Great for comparisons, A/B versions, relationships.

digraph ProcessPaired {
    graph [rankdir=TB, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=paired12, fontname=Arial];
    edge [colorscheme=paired12, penwidth=2];

    subgraph cluster_v1 {
        label="Version 1.x";
        style=filled;
        fillcolor="#F0F0F0";
        V1_Start [fillcolor=1, label="Start v1"];
        V1_Process [fillcolor=1, label="Process v1"];
        V1_End [fillcolor=1, label="End v1"];
        V1_Start -> V1_Process -> V1_End;
    }

    subgraph cluster_v2 {
        label="Version 2.x";
        style=filled;
        fillcolor="#F8F8F8";
        V2_Start [fillcolor=2, label="Start v2"];
        V2_Process [fillcolor=2, label="Process v2"];
        V2_End [fillcolor=2, label="End v2"];
        V2_Start -> V2_Process -> V2_End;
    }

    V1_Start -> V2_Start [label="upgrade", color=4, style=dashed];
}

Command line:

dot -Tsvg colorscheme_paired.dot -o colorscheme_paired.svg

Example 6: Accent8 (qualitative, strong contrasts)

Maximum contrast between elements. For highlighting important differences.

digraph ProcessAccent {
    graph [rankdir=LR, bgcolor="#F5F5F5"];
    node [shape=box, style="rounded,filled", colorscheme=accent8, fontname=Arial, fontcolor=black];
    edge [colorscheme=accent8, penwidth=2];

    Input [fillcolor=1, label="Input"];
    Parse [fillcolor=2, label="Parse"];
    Transform [fillcolor=3, label="Transform"];
    Validate [fillcolor=4, label="Validate"];
    Output [fillcolor=5, label="Output"];

    Input -> Parse [color=1];
    Parse -> Transform [color=2];
    Transform -> Validate [color=3];
    Validate -> Output [color=4];
    Validate -> Parse [color=6, label="retry", style=dashed];
}

Command line:

dot -Tsvg colorscheme_accent.dot -o colorscheme_accent.svg

When to use which color scheme

Scenario Recommended Color Scheme
Different categories, presentations set39, set28, dark28
Technical documentation, wikis pastel19, pastel28
Progression, priorities, levels blues9, greens9, purples9, oranges9
States (ok/warning/error) rdylgn9, rdylbu9, spectral9
Comparisons, A/B versions paired12, paired11
Maximum contrast accent8, set39
Accessibility (color blindness) set2, dark2 (ColorBrewer safe)

Combining color schemes

You can use different schemes for nodes and edges:

node [colorscheme=pastel19, fillcolor=3];
edge [colorscheme=dark28, color=2];

Tip: Always test colors with ColorBrewer to verify accessibility and printability.


Advanced techniques: ports, ranks, compound edges

Ports in records โ€” Connect edges to specific fields of a record using the syntax node:port:

ClassA:field1 -> ClassB:field2;

Force nodes to the same level โ€” Use rank=same to position multiple nodes on the same horizontal line:

{ rank=same; A; B; C; }

Compound edges between clusters โ€” Connect entire clusters instead of individual nodes with lhead and ltail:

edge [lhead=cluster_B, ltail=cluster_A];

Orthogonal edges โ€” Create edges with right angles for an “architect” style:

graph [splines=ortho];

Professional style: practical tips

  • Use coherent palettes.
  • Avoid overly bright gradients.
  • Use Inter, Arial or Roboto for readability.
  • Use ortho for “architect” edges.
  • Maintain adequate margins (nodesep, ranksep).
  • Prefer SVG for quality in blogs.
  • Keep DOT files versioned.

Ready-to-use graphic styles

Here are 5 stylistic variants for the same state diagram, ready to copy and adapt to your diagrams. Each style defines colors, fonts, sizes and shapes to create a coherent look.

Style 1: Corporate Blue (professional, formal)

Blue/gray palette, Arial font, clean style for corporate presentations.

digraph CorporateBlue {
    graph [
        rankdir=LR,
        bgcolor="#F8F9FA",
        fontname="Arial",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#E3F2FD",
        color="#1976D2",
        fontname="Arial",
        fontsize=11,
        fontcolor="#1565C0",
        penwidth=2
    ];
    edge [
        color="#1976D2",
        fontname="Arial",
        fontsize=10,
        fontcolor="#424242"
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Command line:

dot -Tsvg style_corporate.dot -o style_corporate.svg

Style 2: Dark Mode (modern, tech)

Dark background, light text, green/cyan palette for modern UIs and developer tools.

digraph DarkMode {
    graph [
        rankdir=LR,
        bgcolor="#1E1E1E",
        fontname="Consolas",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#2D2D30",
        color="#00D9FF",
        fontname="Consolas",
        fontsize=11,
        fontcolor="#E0E0E0",
        penwidth=2
    ];
    edge [
        color="#00D9FF",
        fontname="Consolas",
        fontsize=10,
        fontcolor="#B0B0B0"
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Command line:

dot -Tsvg style_dark.dot -o style_dark.svg

Style 3: Warm Minimal (soft, readable)

Warm orange/beige palette, sans-serif, great for technical documentation.

digraph WarmMinimal {
    graph [
        rankdir=LR,
        bgcolor="#FFFBF5",
        fontname="Helvetica",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#FFE8CC",
        color="#FF8C42",
        fontname="Helvetica",
        fontsize=11,
        fontcolor="#6B4423",
        penwidth=1.5
    ];
    edge [
        color="#FF8C42",
        fontname="Helvetica",
        fontsize=10,
        fontcolor="#8B5A3C",
        penwidth=1.5
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Command line:

dot -Tsvg style_warm.dot -o style_warm.svg

Style 4: Monochrome (elegant, printable)

Black and white, grayscale gradations, perfect for printing and formal documentation.

digraph Monochrome {
    graph [
        rankdir=LR,
        bgcolor="white",
        fontname="Times-Roman",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#F5F5F5",
        color="#333333",
        fontname="Times-Roman",
        fontsize=11,
        fontcolor="#000000",
        penwidth=2
    ];
    edge [
        color="#333333",
        fontname="Times-Roman",
        fontsize=10,
        fontcolor="#666666",
        penwidth=1.5
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Command line:

dot -Tsvg style_mono.dot -o style_mono.svg

Style 5: Vibrant Gradient (creative, impactful)

Vibrant colors with gradients, great for presentations and visually appealing slides.

digraph VibrantGradient {
    graph [
        rankdir=LR,
        bgcolor="#FAFAFA",
        fontname="Verdana",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#A8E6CF:#56CCF2",
        gradientangle=90,
        color="#2D6A9F",
        fontname="Verdana",
        fontsize=11,
        fontcolor="#1A3A52",
        penwidth=2.5
    ];
    edge [
        color="#9B59B6",
        fontname="Verdana",
        fontsize=10,
        fontcolor="#5B3A72",
        penwidth=2
    ];

    Idle [label="Idle"];
    Processing [label="Processing", fillcolor="#FFD93D:#FF6B9D", gradientangle=90];
    Complete [label="Complete", fillcolor="#6BCF7F:#4ECDC4", gradientangle=90];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Command line:

dot -Tsvg style_vibrant.dot -o style_vibrant.svg

How to use these styles

Copy the graph, node, edge block of the style you prefer and apply it to your diagrams. You can then customize:

  • Colors: replace hex codes with your palette
  • Fonts: use fontname="FontName" (Arial, Helvetica, Courier, Times, Verdana, Consolas)
  • Sizes: fontsize for text, penwidth for border and arrow thickness
  • Shape: box, ellipse, circle, diamond, cylinder, record
  • Gradients: use fillcolor="color1:color2" with gradientangle (only some output formats)

Notes on font compatibility

Fonts must be installed on the system where you generate images:

  • Universal fonts (work everywhere): Arial, Helvetica, Times, Times-Roman, Courier
  • Modern fonts (verify availability): Verdana, Consolas, Roboto, Inter
  • Windows: most fonts are already installed
  • macOS: excellent support for standard fonts
  • Linux: install fonts-liberation or fonts-dejavu to have Arial/Helvetica equivalents
  • CI/CD: use base fonts or include fonts in Docker container

If a font is not available, Graphviz uses a fallback (usually Times). To be safe, always use base fonts or test generation on the production environment.


Workflow: how to integrate Graphviz in real work

  1. Put .gv files in the repo.

  2. Generate SVGs automatically in CI:

    dot -Tsvg diagram.gv -o diagram.svg
    
  3. Inject SVGs into documentation (README, wiki, blog).

  4. Update diagrams with each refactoring.

  5. Use diff and versioning of DOT files as you would with code.


Troubleshooting: common errors and solutions

Error: “syntax error in line X near…”

  • Cause: Invalid DOT syntax
  • Solution: Check for missing semicolons, unclosed braces, unmatched quotes
  • Example: A -> B must end with ; โ†’ A -> B;

Error: “Warning: Unable to find font…”

  • Cause: The specified font is not installed on the system
  • Solution: Use universal fonts (Arial, Helvetica, Times) or install the required font
  • Verify available fonts: dot -v shows available fonts

The diagram is too big/small

  • Solution 1: Add graph [size="8,6"] to limit dimensions (in inches)
  • Solution 2: Use graph [ratio=compress] to compress automatically
  • Solution 3: Generate PNG with custom DPI: dot -Tpng -Gdpi=150 file.dot -o file.png

Arrows overlap nodes

  • Solution: Add graph [overlap=false, splines=true] (see “Avoiding overlaps” section)

Nodes are all aligned horizontally instead of vertically

  • Solution: Use graph [rankdir=TB] for top-to-bottom (default is LR = left-to-right)

The cluster doesn’t appear

  • Cause: Cluster name doesn’t start with cluster_
  • Solution: Rename subgraph mygroup to subgraph cluster_mygroup

SVG output too large (file size)

  • Cause: SVG with many elements
  • Solution 1: Use PNG instead of SVG for very complex graphs
  • Solution 2: Optimize with svgo: svgo input.svg -o output.svg

Graph doesn’t generate (no output, no error)

  • Cause: Incorrect command or wrong redirect
  • Verify: Use -v for verbose: dot -v -Tsvg input.dot -o output.svg
  • Quick test: echo "digraph{A->B}" | dot -Tsvg > test.svg

Edge labels are not visible

  • Cause: Labels too long or font too small
  • Solution: Increase fontsize on edges or use \n to break labels on multiple lines

DOT Templates + Graphviz Commands (CLI)

Each template includes:

  1. DOT snippet

  2. CLI command to generate the image

For consistency I use SVG format, but you can replace -Tsvg with:

  • -Tpng
  • -Tpdf
  • -Tjpg
  • -Tgif

And you can save the DOT input in template.dot or use pipe.


Flowchart

Template 1 โ€“ Basic process

digraph FlowBasic {
    graph [rankdir=TB];
    node [shape=rectangle, style=rounded, fontsize=12];

    Start [label="Start", shape=circle];
    Step1 [label="Input validation"];
    Step2 [label="Process request"];
    Step3 [label="Persist data"];
    End [label="End", shape=doublecircle];

    Start -> Step1 -> Step2 -> Step3 -> End;
}

Command line:

dot -Tsvg FlowBasic.dot -o FlowBasic.svg

Template 2 โ€“ Branching (if/else)

digraph FlowIfElse {
    graph [rankdir=TB];
    node [fontsize=12, style=rounded];

    Start [shape=circle];
    Check [shape=diamond, label="Is valid?"];
    A [label="Handle valid case"];
    B [label="Handle error"];
    End [shape=doublecircle];

    Start -> Check;
    Check -> A [label="Yes"];
    Check -> B [label="No"];
    A -> End;
    B -> End;
}

Command line:

dot -Tsvg FlowIfElse.dot -o FlowIfElse.svg

Template 3 โ€“ Process with sections

digraph FlowSections {
    graph [rankdir=TB];
    node [fontsize=11, style=rounded];

    subgraph cluster_input {
        label="Input Stage";
        color=lightgrey;
        style=filled;

        A1 [label="Receive request"];
        A2 [label="Validate payload"];
        A1 -> A2;
    }

    subgraph cluster_processing {
        label="Processing Stage";
        color=lightblue;
        style=filled;

        P1 [label="Transform data"];
        P2 [label="Apply business rules"];
        P1 -> P2;
    }

    subgraph cluster_output {
        label="Output Stage";
        color=lightyellow;
        style=filled;

        O1 [label="Persist"];
        O2 [label="Return response"];
        O1 -> O2;
    }

    A2 -> P1 -> O1;
}

Command line:

dot -Tsvg FlowSections.dot -o FlowSections.svg

State Machine

Template 4 โ€“ Basic state machine

digraph StateMachine {
    graph [rankdir=LR];
    node [shape=circle, fontsize=12];

    Idle;
    Loading;
    Error;
    Success;

    Idle -> Loading [label="start"];
    Loading -> Success [label="ok"];
    Loading -> Error [label="fail"];
    Error -> Idle [label="retry"];
}

Command line:

dot -Tsvg StateMachine.dot -o StateMachine.svg

Template 5 โ€“ Nested states

digraph NestedStates {
    graph [rankdir=LR];
    node [fontsize=11];

    subgraph cluster_ready {
        label="Ready state";
        style=dashed;
        R1 [shape=circle, label="Idle"];
        R2 [shape=circle, label="Primed"];
        R1 -> R2 [label="prepare"];
    }

    subgraph cluster_active {
        label="Active state";
        style=dashed;
        A1 [shape=circle, label="Running"];
        A2 [shape=circle, label="Paused"];
        A1 -> A2 [label="pause"];
        A2 -> A1 [label="resume"];
    }

    R2 -> A1 [label="activate"];
}

Command line:

dot -Tsvg NestedStates.dot -o NestedStates.svg

Sequence Diagram (DOT)

Template 6 โ€“ Horizontal sequence

digraph Sequence {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    Client -> API [label="POST /login"];
    API -> AuthService [label="Check credentials"];
    AuthService -> DB [label="Query user"];
    DB -> AuthService [label="Result"];
    AuthService -> API [label="Token"];
    API -> Client [label="200 OK"];
}

Command line:

dot -Tsvg Sequence.dot -o Sequence.svg

Template 7 โ€“ Sequence with activations

digraph SequenceActivation {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    User -> Frontend [label="Login"];
    Frontend -> Backend [label="POST /login"];
    Backend -> Backend [label="validate()"];
    Backend -> DB [label="SELECT user"];
    DB -> Backend [label="row found"];
    Backend -> Frontend [label="JWT"];
    Frontend -> User [label="Welcome"];
}

Command line:

dot -Tsvg SequenceActivation.dot -o SequenceActivation.svg

Dependency Graph

Template 8 โ€“ Modules

digraph DependencyTree {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=12];

    App -> ModuleA;
    App -> ModuleB;
    ModuleA -> LibA;
    ModuleA -> LibB;
    ModuleB -> LibB;
}

Command line:

dot -Tsvg DependencyTree.dot -o DependencyTree.svg

Template 9 โ€“ Microservices

digraph MicroservicesDep {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Gateway -> Auth;
    Gateway -> Orders;
    Auth -> UsersDB;
    Orders -> ProductsService;
    Orders -> Payments;
    Payments -> BankAPI;
}

Command line:

dot -Tsvg MicroservicesDep.dot -o MicroservicesDep.svg

Architecture Diagram

Template 10 โ€“ Layered

digraph Layered {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=12];

    subgraph cluster_presentation {
        label="Presentation Layer";
        style=filled;
        color=lightyellow;
        UI;
        API;
    }

    subgraph cluster_business {
        label="Business Layer";
        style=filled;
        color=lightblue;
        Services;
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        color=lightgrey;
        DB;
        Cache;
    }

    UI -> API -> Services -> DB;
    Services -> Cache;
}

Command line:

dot -Tsvg Layered.dot -o Layered.svg

Template 11 โ€“ Hexagonal

digraph Hexagonal {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    AppCore [label="Core Domain"];
    PortIn [label="Inbound Ports"];
    PortOut [label="Outbound Ports"];
    AdapterIn [label="Inbound Adapters"];
    AdapterOut [label="Outbound Adapters"];
    DB [label="Database"];
    UI [label="Frontend/UI"];

    UI -> AdapterIn -> PortIn -> AppCore;
    AppCore -> PortOut -> AdapterOut -> DB;
}

Command line:

dot -Tsvg Hexagonal.dot -o Hexagonal.svg

ER Diagrams

Template 12 โ€“ 1:N

digraph ER_OneToMany {
    graph [rankdir=LR];
    node [shape=record, fontsize=11];

    User [label="{User|id PK|name|email}"];
    Order [label="{Order|id PK|user_id FK|total}"];

    User -> Order [label="1:N"];
}

Command line:

dot -Tsvg ER_OneToMany.dot -o ER_OneToMany.svg

Template 13 โ€“ N:N

digraph ER_ManyToMany {
    graph [rankdir=LR];
    node [shape=record, fontsize=11];

    Student [label="{Student|id PK|name}"];
    Course [label="{Course|id PK|title}"];
    Enroll [label="{Enroll|student_id FK|course_id FK}"];

    Student -> Enroll;
    Course -> Enroll;
}

Command line:

dot -Tsvg ER_ManyToMany.dot -o ER_ManyToMany.svg

Call Graph

Template 14 โ€“ Basic

digraph CallGraph {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=11];

    main -> init;
    main -> loadConfig;
    loadConfig -> readFile;
    readFile -> parseJson;
}

Command line:

dot -Tsvg CallGraph.dot -o CallGraph.svg

Template 15 โ€“ With categories

digraph CategorizedCalls {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=11];

    subgraph cluster_io {
        label="I/O Functions";
        color=lightgrey;
        readFile;
        writeFile;
    }

    subgraph cluster_logic {
        label="Business Logic";
        color=lightblue;
        compute;
        validate;
    }

    main -> compute -> validate;
    compute -> readFile;
    validate -> writeFile;
}

Command line:

dot -Tsvg CategorizedCalls.dot -o CategorizedCalls.svg

Network Diagram

Template 16 โ€“ Basic

digraph Network {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Client -> LoadBalancer;
    LoadBalancer -> AppServer1;
    LoadBalancer -> AppServer2;
    AppServer1 -> DB;
    AppServer2 -> DB;
}

Command line:

dot -Tsvg Network.dot -o Network.svg

Template 17 โ€“ With protocols

digraph NetworkProto {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    Client -> API [label="HTTPS"];
    API -> Auth [label="gRPC"];
    API -> Orders [label="REST"];
    Orders -> DB [label="TCP"];
}

Command line:

dot -Tsvg NetworkProto.dot -o NetworkProto.svg

Timeline / Roadmap

Template 18 โ€“ Timeline

digraph Timeline {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Start -> Milestone1 -> Milestone2 -> Milestone3 -> Release;
}

Command line:

dot -Tsvg Timeline.dot -o Timeline.svg

Template 19 โ€“ Roadmap

digraph Roadmap {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    subgraph cluster_backend {
        label="Backend";
        B1 [label="Auth module"];
        B2 [label="Payments"];
    }

    subgraph cluster_frontend {
        label="Frontend";
        F1 [label="Login UI"];
        F2 [label="Dashboard"];
    }

    B1 -> B2;
    F1 -> F2;
}

Command line:

dot -Tsvg Roadmap.dot -o Roadmap.svg

Mind Map

Template 20 โ€“ Mind map

graph MindMap {
    layout=twopi;
    rankdir=LR;
    node [shape=box, style=rounded, fontsize=11];

    Central -- Idea1;
    Central -- Idea2;
    Central -- Idea3;
    Idea2 -- Sub1;
    Idea2 -- Sub2;
}

Command line:

dot -Ktwopi -Tsvg MindMap.dot -o MindMap.svg

Component Diagram

Template 21 โ€“ Components

digraph Components {
    graph [rankdir=LR];
    node [shape=component, fontsize=11];

    UI -> API;
    API -> Service;
    Service -> DB;
}

Command line:

dot -Tsvg Components.dot -o Components.svg

Class Diagram

Template 22 โ€“ UML class-like

digraph Classes {
    graph [rankdir=TB];
    node [shape=record, fontsize=11];

    Person [label="{Person|name:string|age:int}"];
    Student [label="{Student|grade:int}"];
    Person -> Student;
}

Command line:

dot -Tsvg Classes.dot -o Classes.svg

Layouts

Template 23 โ€“ Horizontal

digraph Horizontal {
    graph [rankdir=LR];
    node [shape=box, style=rounded];
}

Command line:

dot -Tsvg Horizontal.dot -o Horizontal.svg

Template 24 โ€“ Vertical

digraph Vertical {
    graph [rankdir=TB];
    node [shape=box, style=rounded];
}

Command line:

dot -Tsvg Vertical.dot -o Vertical.svg

Template 25 โ€“ Circular

graph Circular {
    layout=circo;
    node [shape=box, style=rounded];
}

Command line:

dot -Kcirco -Tsvg Circular.dot -o Circular.svg

Professional styles

Template 26 โ€“ Modern theme

digraph Modern {
    graph [rankdir=LR];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#eef3f8",
        color="#6a8bbf",
        fontsize=11
    ];
    edge [color="#6a8bbf"];

    A -> B -> C;
}

Command line:

dot -Tsvg Modern.dot -o Modern.svg

Template 27 โ€“ Dark Theme

digraph Dark {
    bgcolor="#1e1e1e";
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#333333",
        fontcolor="white",
        color="#777777",
        fontsize=11
    ];
    edge [color="#999999"];

    A -> B -> C;
}

Command line:

dot -Tsvg Dark.dot -o Dark.svg


Useful resources

Official documentation

Online tools

Integrations and libraries

  • Graphviz Visual Editor (VSCode): Extension for live preview in Visual Studio Code
  • PlantUML: plantuml.com โ€” Uses Graphviz for UML rendering
  • Mermaid: mermaid.js.org โ€” JavaScript-based alternative to Graphviz for graphs in Markdown
  • Python graphviz: graphviz.readthedocs.io โ€” Python library to generate graphs programmatically
  • Go graphviz: github.com/goccy/go-graphviz โ€” Go binding for Graphviz

Gallery and examples

Community and support

  • Stack Overflow: Tag graphviz โ€” Community questions and answers
  • Reddit r/graphviz: reddit.com/r/graphviz โ€” Discussions, examples and help

Complementary tools


Article written by Daniele Teti โ€” danieleteti.it

Comments

comments powered by Disqus