D2 Diagramming Reference

Declarative diagramming with D2. Shapes, containers, sequence diagrams, and Antora integration via Kroki.

Basics

Shape declarations and connections
server: Web Server
database: PostgreSQL {
  shape: cylinder
}
server -> database: queries

Shapes are declared by name. Braces add properties. Arrows (->, , <→) create connections.

Connection labels and styling
client -> lb: HTTPS {
  style.stroke-dash: 3
}
lb -> app1: HTTP
lb -> app2: HTTP
app1 -> db
app2 -> db

Shapes

Shape types — rectangle, cylinder, circle, diamond, and more
api: REST API {shape: hexagon}
db: Database {shape: cylinder}
decision: Approve? {shape: diamond}
queue: Message Queue {shape: queue}
cloud: AWS {shape: cloud}
user: Admin {shape: person}
docs: Manual {shape: page}
pkg: Package {shape: package}

Containers (Nesting)

Nested containers for logical grouping
network: Network Layer {
  fw: Firewall
  lb: Load Balancer
  fw -> lb
}
application: App Layer {
  api: API Server
  worker: Background Worker
}
network.lb -> application.api

Containers group related components. Access nested shapes with dot notation.

Layouts

Layout engine selection via CLI
d2 --layout=elk diagram.d2 output.svg     # Hierarchical (default)
d2 --layout=dagre diagram.d2 output.svg   # Directed acyclic graph
Grid layout for structured placement
grid: {
  grid-rows: 2
  grid-columns: 3
  cell1
  cell2
  cell3
  cell4
  cell5
  cell6
}

Styling with Catppuccin Mocha

Catppuccin Mocha palette for consistent theming
vars: {
  d2-config: {
    theme-id: 200
  }
}

server: Web Server {
  style: {
    fill: "#1e1e2e"       # Base
    stroke: "#89b4fa"     # Blue
    font-color: "#cdd6f4" # Text
  }
}
database: PostgreSQL {
  shape: cylinder
  style: {
    fill: "#1e1e2e"
    stroke: "#a6e3a1"     # Green
    font-color: "#cdd6f4"
  }
}
server -> database: queries {
  style: {
    stroke: "#f5c2e7"     # Pink
  }
}

Sequence Diagrams

Sequence diagram with actors and messages
shape: sequence_diagram

client: Client
server: API Server
db: Database

client -> server: POST /login
server -> db: SELECT user
db -> server: user record
server -> client: 200 OK + JWT

Icons and Images

Icon from a URL
k8s: Kubernetes {
  icon: https://icons.terrastruct.com/tech/kubernetes.svg
}

CLI Commands

Render to SVG and PNG
d2 diagram.d2 diagram.svg
d2 --format png diagram.d2 diagram.png
Watch mode — re-renders on file change
d2 --watch diagram.d2 diagram.svg
# Opens browser with live reload
Dark theme rendering
d2 --theme 200 diagram.d2 dark.svg     # Dark Mauve theme
d2 --dark-theme 200 diagram.d2 out.svg # Auto dark/light

Quick Render from Terminal

d2 requires a file path — no stdin support. Heredoc to a temp file bridges the gap.

Prototype a diagram inline
cat << 'EOF' > /tmp/diagram.d2
direction: right
client -> switch: 802.1X
switch -> ise: RADIUS {
  style.stroke: "#a6e3a1"
  style.animated: true
}
ise -> dc: LDAPS
EOF
d2 --theme=200 /tmp/diagram.d2 /tmp/diagram.svg && xdg-open /tmp/diagram.svg

Single-quoted 'EOF' prevents shell expansion — {braces} and $vars pass through literally to D2. The && chain opens the browser only on successful render.

Watch mode — live reload as you edit the temp file
cat << 'EOF' > /tmp/diagram.d2
a -> b -> c
EOF
d2 --watch --theme=200 /tmp/diagram.d2 /tmp/diagram.svg
# Opens browser — saves to /tmp/diagram.d2 trigger re-render
Promote prototype to project
cp /tmp/diagram.d2 docs/modules/ROOT/examples/diagrams/network/new-diagram.d2
d2 --theme=200 \
  docs/modules/ROOT/examples/diagrams/network/new-diagram.d2 \
  docs/modules/ROOT/images/diagrams/d2/network/new-diagram.svg
Batch render a category
for f in docs/modules/ROOT/examples/diagrams/network/*.d2; do
  out="docs/modules/ROOT/images/diagrams/d2/network/$(basename "${f%.d2}.svg")"
  d2 --theme=200 "$f" "$out" && printf "  → %s\n" "$out"
done

Integration with Antora (Kroki)

D2 diagram block in AsciiDoc via Kroki
[d2,target=network-diagram,format=svg]
....
server -> database: SQL
server -> cache: Redis
....

Kroki renders the D2 source during make build. The diagram appears inline as SVG. Requires Kroki running (handled by make).

See Also