D2 is a modern diagram scripting language that lets you turn plain text into architecture diagrams. If you've ever struggled with dragging boxes around in a GUI tool, only to lose your layout when you add one new component, D2 solves that problem. You write code, it draws the diagram. Simple as that. For software architects and developers who already think in systems, this approach feels natural and the diagrams stay version-controlled alongside the codebase.
What Exactly Is the D2 Diagram Language?
D2 (short for "Declarative Diagramming") is an open-source, text-based diagram language created by Terrastruct. Unlike traditional diagramming tools, D2 uses a straightforward declarative syntax. You describe nodes, connections, labels, and shapes then a compiler turns that into an SVG or PNG image.
Think of it as a markup language specifically built for diagrams. If you've used Mermaid for system architecture diagrams, D2 offers a similar workflow but with more layout control, richer styling options, and better handling of complex architectures.
D2 supports:
- Automatic layout engines (dagre, elk)
- Directional and bidirectional connections
- Shape customization and theming
- Container nesting (essential for showing microservices, layers, or bounded contexts)
- SQL table shapes, class diagrams, sequence diagrams, and more
Why Would You Use D2 for Software Architecture?
Most architecture diagrams die the moment someone creates them in a slide deck. They get outdated, nobody knows who last edited them, and they live in some folder nobody checks. D2 fixes this because the source is a plain text file. You can diff it in Git, review changes in pull requests, and regenerate the image in CI/CD.
This is especially useful when you're documenting systems with many components. Think microservice architectures, event-driven designs, or multi-layered platforms. With D2, adding a new service to your diagram is as simple as adding a few lines of text.
If you're comparing diagram-as-code options, the C4 model DSL notation and D2 each have strengths. C4 notation excels at enterprise-level abstraction layers, while D2 gives you more visual control and flexibility for detailed technical diagrams.
Basic D2 Syntax Every Architect Should Know
D2's syntax is minimal. Here's how the core building blocks work:
Declaring Nodes
Every word (or quoted phrase) becomes a node:
api-gateway
user-service
order-service
This alone creates three separate boxes on the diagram.
Creating Connections
Use arrows to link nodes:
api-gateway -> user-service
api-gateway -> order-service
This draws arrows from the API gateway to each downstream service.
Adding Labels and Shapes
database: User Database {
shape: cylinder
}
user-service -> database: reads/writes
The label inside the curly braces becomes the displayed name. You can assign shapes like cylinder, hexagon, diamond, or cloud to make the meaning visually obvious.
Practical D2 Code Examples for Common Architecture Patterns
A Simple Microservices Architecture
Here's a D2 code example showing a basic microservices layout with an API gateway, two services, and a shared database:
direction: right
client: Client Application {
shape: rectangle
}
gateway: API Gateway {
shape: hexagon
}
client -> gateway
services: Microservices {
user-service: User Service
order-service: Order Service
inventory-service: Inventory Service
}
gateway -> services.user-service
gateway -> services.order-service
gateway -> services.inventory-service
db: Shared Database {
shape: cylinder
}
services.user-service -> db
services.order-service -> db
services.inventory-service -> db
This example shows container nesting the three services live inside a "Microservices" container block. The layout engine positions them automatically.
A Layered Architecture Diagram
direction: down
presentation: Presentation Layer {
web-app: Web Application
mobile-app: Mobile App
}
application: Application Layer {
auth-service: Auth Service
business-logic: Business Logic
}
data: Data Layer {
postgres: PostgreSQL {
shape: cylinder
}
redis: Redis Cache {
shape: cylinder
}
}
presentation -> application
application.data -> data.postgres
application.auth-service -> data.redis
Setting direction: down forces a top-to-bottom layout, which reads naturally for layered architectures.
Event-Driven Architecture with Message Queues
producer: Order Service {
shape: rectangle
}
queue: Message Broker {
shape: queue
}
consumer-a: Notification Service
consumer-b: Analytics Service
consumer-c: Inventory Service
producer -> queue: publishes events
queue -> consumer-a
queue -> consumer-b
queue -> consumer-c
The queue shape in D2 renders a message queue visually, making it immediately clear this is an event-driven design.
An Infrastructure Overview with Cloud Shapes
cloud: AWS Cloud {
shape: cloud
vpc: VPC {
subnet-a: Public Subnet {
alb: Application Load Balancer {
shape: hexagon
}
}
subnet-b: Private Subnet {
eks: EKS Cluster {
shape: rectangle
}
rds: RDS {
shape: cylinder
}
}
}
}
users: End Users {
shape: person
}
users -> cloud.vpc.subnet-a.alb
cloud.vpc.subnet-a.alb -> cloud.vpc.subnet-b.eks
cloud.vpc.subnet-b.eks -> cloud.vpc.subnet-b.rds
Deep nesting like this is where D2 really shines. The indented structure mirrors the infrastructure hierarchy, and the layout engine keeps it readable.
How Does D2 Compare to Mermaid for Architecture Diagrams?
Both are diagram-as-code tools, but they serve slightly different needs:
- Layout control: D2 gives you explicit direction settings (
right,down) and better automatic spacing. Mermaid's layout is more rigid. - Nesting: D2 handles container nesting natively with curly braces. Mermaid's
graphsyntax doesn't support nested grouping as cleanly. - Styling: D2 offers shape customization, themes, and CSS-like styling. Mermaid is more limited here.
- Ecosystem: Mermaid has wider tooling support (GitHub, Notion, Obsidian). D2 is newer but growing. The Mermaid code for system architecture diagrams article covers that tool in depth.
- Diagram types: Both support flowcharts and sequence diagrams. D2 also handles SQL table shapes and class diagrams well.
For complex, deeply nested software architecture diagrams with custom styling, D2 tends to produce cleaner results. For quick inline diagrams in documentation platforms, Mermaid's ecosystem support is hard to beat.
Common Mistakes When Writing D2 Architecture Diagrams
Over-Nesting Containers
D2 supports deep nesting, but four or five levels deep makes diagrams hard to read. Aim for two or three levels at most. If your architecture needs deeper abstraction, consider splitting into multiple linked diagrams.
Forgetting to Set Direction
Without a direction directive, D2 uses its default layout, which may not match the mental model you want. Always set direction: right or direction: down explicitly.
Making Diagrams Too Detailed
Putting every single endpoint, method name, or config variable into one diagram defeats the purpose. Use D2 to show structure and relationships. Keep details for API documentation or sequence diagrams.
Not Using Labels on Connections
A line between two nodes means nothing without context. Always add labels to your arrows:
service-a -> service-b: gRPC (port 50051)
Ignoring Shape Semantics
Using rectangles for everything makes diagrams harder to scan. Use cylinder for databases, cloud for cloud services, hexagon for gateways or load balancers, and person for actors. Visual conventions speed up comprehension.
Tips for Getting More Out of D2
- Use connections to reference nested nodes:
gateway -> services.user-servicelets you target nodes inside containers without duplicating them. - Apply themes: D2 ships with built-in themes. Add
theme-id: 4at the top of your file for a polished look without manual styling. - Watch mode for iteration: Running
d2 --watch diagram.d2 diagram.svgauto-regenerates the output every time you save. Great for rapid iteration. - Use
near: top-centeron labels: Title labels and annotations can be positioned precisely using thenearattribute. - Version control your .d2 files: Treat them like code. Commit them, review changes, and keep a history of how your architecture evolves.
- Split large diagrams: If your architecture has 30+ services, create separate D2 files per bounded context or domain, then cross-reference where needed.
How Do You Render D2 Diagrams?
You have several options:
- CLI tool: Install via
brew install d2(macOS) or from the D2 GitHub repository. Then rund2 input.d2 output.svg. - VS Code extension: The official D2 extension provides live preview as you type.
- Terrastruct's cloud platform: A hosted editor with collaboration features built around D2.
- CI/CD pipeline: Add a D2 compile step to your build pipeline so architecture diagrams always stay current with your codebase.
Quick-Start Checklist for D2 Architecture Diagrams
- Install D2 via your package manager or download from GitHub
- Create your first
.d2file with nodes and connections - Set a
directionat the top of your file - Use container nesting for logical groupings (services, layers, zones)
- Add labels to every connection arrow
- Use shape semantics cylinders for databases, clouds for cloud services
- Apply a theme for a clean, consistent look
- Render with
d2 --watchduring editing, then export final SVG/PNG - Commit the
.d2source file to version control - Set up a CI step to regenerate diagrams on merge
Next step: Pick one real system you're working on right now and write its architecture in D2. Start with five nodes and two levels of nesting. Render it, share it with your team, and iterate. You'll have a living, version-controlled architecture diagram within the hour.
Mermaid Code for System Architecture Diagrams - Syntax and Examples
C4 Model Dsl Notation for Enterprise Architecture
Structurizr Dsl vs Plantuml for Microservices Architecture
Plantuml Cloud Architecture Syntax Guide
How to Write Flowchart Code From Scratch: a Complete Beginner's Tutorial
Mermaid Flowchart Syntax Examples for Github Repositories