Diagrams as code keeps architecture pictures in plain text next to the source they describe. This page shows the notation, one diagram written in five tools, a CI rendering setup, and honest pros and cons.
Diagrams as code means writing a diagram as plain text — boxes, arrows and labels in a small language — and letting a tool draw the picture. The text lives in git next to the code it describes. Engineers write and review it; anyone reading documentation sees the rendered image.
The main tools are Mermaid (renders natively in GitHub, GitLab and many wikis), PlantUML (the broadest UML coverage), Structurizr DSL (C4 architecture models), D2 (modern syntax and layouts) and Graphviz (the original DOT language, still behind many tools).
Every tool has its own syntax, but the ideas are the same: declare nodes with labels, connect them with edges, and attach style hints such as shape or line style. The legend uses Mermaid syntax. Layout — where boxes go — is decided by the tool's algorithm, not by you. That is the biggest difference from drawing tools.
Read the legend left to right: the text on the left is what you type, the shape in the middle is what the renderer draws, and the label on the right names the concept. Square brackets give a box its label, arrows connect node identifiers, and special bracket pairs pick shapes — [( )] is a cylinder for storage. Identifiers such as A stay short; labels carry the readable names.
Walkthrough. The customer calls the Shop API. The API charges the card through the payment service, which talks to the card network, and writes the order to the database. A dashed arrow shows the order event going to an email queue asynchronously. Below, the same diagram is written in all five tools so you can compare them.
Mermaid (renders in GitHub/GitLab Markdown, the Mermaid CLI mmdc, MkDocs, Docusaurus):
flowchart LR
C[Customer] --> API[Shop API]
API --> PAY[Payment service]
PAY --> NET[Card network]
API --> DB[(Orders DB)]
DB -.-> Q[Email queue]
PlantUML (Java renderer, or a PlantUML server; widely supported in Confluence, IntelliJ and VS Code):
@startuml
actor Customer
component "Shop API" as API
component "Payment service" as PAY
database "Orders DB" as DB
queue "Email queue" as Q
Customer --> API
API --> PAY
API --> DB
DB ..> Q
@enduml
Structurizr DSL (rendered by Structurizr Lite or exported to PlantUML/Mermaid). Notice it defines a model first and then views of it:
workspace {
model {
customer = person "Customer"
shop = softwareSystem "Online Shop" {
api = container "Shop API"
db = container "Orders DB" "" "PostgreSQL" "Database"
}
pay = softwareSystem "Payment service"
customer -> api "Checks out"
api -> pay "Charges card"
api -> db "Writes order"
}
views {
container shop { include * autolayout lr }
}
}
D2 (the d2 CLI; supports several layout engines):
Customer -> Shop API
Shop API -> Payment service
Payment service -> Card network
Shop API -> Orders DB
Orders DB -> Email queue: {style.stroke-dash: 4}
Orders DB.shape: cylinder
Graphviz DOT (the dot command):
digraph shop {
rankdir=LR;
Customer -> "Shop API";
"Shop API" -> "Payment service" -> "Card network";
"Shop API" -> "Orders DB";
"Orders DB" [shape=cylinder];
"Orders DB" -> "Email queue" [style=dashed];
}
Walkthrough. Diagram sources sit in a docs/ folder. On a pull request, reviewers see a text diff ("added an arrow from API to cache"). A CI job renders each file to SVG and publishes it with the docs. A minimal GitHub Actions step:
- name: Render diagrams
run: |
npm install -g @mermaid-js/mermaid-cli
for f in docs/diagrams/*.mmd; do
mmdc -i "$f" -o "${f%.mmd}.svg"
done
Many teams skip rendering for Mermaid entirely, because GitHub and GitLab render ```mermaid blocks inside Markdown files automatically.
| Tool | Best for | Renders where | Notes |
|---|---|---|---|
| Mermaid | Flowcharts, sequence, ER, state, quick docs | GitHub, GitLab, many wikis, browser JS | Lowest friction; limited layout control |
| PlantUML | Full UML set, sequence diagrams | Java or server; IDE plugins, Confluence | Most diagram types; older-looking default style |
| Structurizr DSL | C4 architecture models with many views | Structurizr Lite / cloud, exporters | Model once, many consistent views |
| D2 | Polished architecture diagrams | d2 CLI, playground | Modern syntax, themes, multiple layout engines |
| Graphviz | Generated graphs (dependencies, pipelines) | dot CLI, libraries in most languages | Great auto-layout; plain styling |
Pros
Cons
When to use: architecture, sequence, ER and flow diagrams that live alongside code and change with it. When not to: early brainstorming, one-off presentation graphics, or pixel-precise layouts — use a drawing tool such as draw.io or Excalidraw there.
A practical tip: keep each diagram small and focused on one question ("what happens at checkout?"), and split large systems into several views. Small diagrams lay out well automatically, and a reviewer can spot when one has gone stale.