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 graph syntax 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-service lets you target nodes inside containers without duplicating them.
  • Apply themes: D2 ships with built-in themes. Add theme-id: 4 at the top of your file for a polished look without manual styling.
  • Watch mode for iteration: Running d2 --watch diagram.d2 diagram.svg auto-regenerates the output every time you save. Great for rapid iteration.
  • Use near: top-center on labels: Title labels and annotations can be positioned precisely using the near attribute.
  • 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:

  1. CLI tool: Install via brew install d2 (macOS) or from the D2 GitHub repository. Then run d2 input.d2 output.svg.
  2. VS Code extension: The official D2 extension provides live preview as you type.
  3. Terrastruct's cloud platform: A hosted editor with collaboration features built around D2.
  4. 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 .d2 file with nodes and connections
  • Set a direction at 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 --watch during editing, then export final SVG/PNG
  • Commit the .d2 source 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.