d2

Use when writing, generating, reviewing, or improving D2 diagram code. Trigger when the user asks to create architecture diagrams, flowcharts, sequence diagrams, ER diagrams, class diagrams, or any diagram using D2 syntax. Also trigger when working with .d2 files or when the d2_render MCP tool is available.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "d2" with this command: npx skills add itsjool/d2-mcp/itsjool-d2-mcp-d2

D2 Diagram Language Reference

D2 is a declarative diagram scripting language that compiles to SVG. Text → diagrams. Docs: https://d2lang.com | Playground: https://play.d2lang.com


Core Syntax

Shapes

# Bare identifier = rectangle by default
server

# With a display label (key vs label)
server: "API Server"

# Set shape type
db: {
  shape: cylinder
}

# Multiple on one line
web; app; db

Available shape types: rectangle (default), square, circle, oval, diamond, hexagon, cloud, cylinder, queue, package, parallelogram, document, page, step, callout, stored_data, person, c4-person, sql_table, class, sequence_diagram, image

Connections

A -> B          # directed arrow
A <- B          # reverse
A -- B          # undirected line
A <-> B         # bidirectional

A -> B: label   # with label

# Chaining
A -> B -> C -> D

# Multiple connections (creates separate arrows, not override)
A -> B
A -> B          # second distinct arrow

# Referencing a specific connection (0-indexed)
(A -> B)[0].style.stroke: red

Containers (nesting)

cloud: {
  label: "AWS"
  vpc: {
    web: "Web Tier"
    app: "App Tier"
    web -> app
  }
}

# Cross-container connections using _ (parent reference)
cloud: {
  aws: {
    db
    db -> _.gcloud.backup    # _ = parent scope
  }
  gcloud: {
    backup
  }
}

Text and Markdown

# Standalone markdown block
explanation: |md
  ## Architecture Overview
  This diagram shows the **three-tier** architecture.
  - Web tier
  - App tier
  - Data tier
|

# LaTeX / math
formula: |latex
  \frac{\partial f}{\partial x} = 2x
|

Style Reference

All styles live under the style key:

my_shape: {
  style: {
    fill: "#4a90d9"          # background color
    stroke: "#2c5f8a"        # border color
    stroke-width: 2
    stroke-dash: 5           # dashed border
    border-radius: 8         # rounded corners
    font-size: 14
    font-color: white
    opacity: 0.9
    shadow: true
    bold: true
    italic: false
    3d: true                 # rectangles/squares only
    multiple: true           # stacked visual effect
    double-border: true      # rectangles and ovals only
    text-transform: uppercase
  }
}

Connection styles:

A -> B: {
  style: {
    stroke: red
    stroke-width: 3
    stroke-dash: 5
    animated: true           # flowing animation in SVG
    bold: true
    font-color: "#666"
  }
}

Arrowheads:

A -> B: {
  source-arrowhead: {
    shape: diamond
    style.filled: true
  }
  target-arrowhead: {
    shape: circle
  }
}

Arrowhead shapes: triangle (default), arrow, diamond, circle, box, cf-one, cf-many, cf-one-required, cf-many-required, cross


Global Styling with Globs

Apply styles to all shapes or connections at once:

# Style all shapes
*.style.fill: "#f0f4ff"
*.style.stroke: "#3b5bdb"
*.style.border-radius: 6

# Style all connections
(* -> *)[*].style.stroke: "#888"
(* -> *)[*].style.animated: true

# Scoped globs (only inside a container)
cloud: {
  *.style.fill: "#e8f5e9"
}

Variables and Substitutions

vars: {
  primary: "#3b5bdb"
  secondary: "#74c0fc"
  accent: "#f06595"

  # In-file config (overridden by CLI flags)
  d2-config: {
    layout-engine: elk
    theme-id: 0
  }
}

server: {
  style.fill: ${primary}
  style.stroke: ${secondary}
}

Reusable Style Classes

classes: {
  important: {
    style: {
      stroke: red
      stroke-width: 3
      bold: true
    }
  }
  faded: {
    style: {
      opacity: 0.4
    }
  }
}

# Apply to shapes
critical_db.class: important
legacy_service.class: faded

# Apply multiple (left-to-right, later wins)
service.class: [important; faded]

# Apply to connections
A -> B: {class: important}

SQL Tables (ER Diagrams)

users: {
  shape: sql_table
  id: int {constraint: primary_key}
  email: varchar {constraint: unique}
  name: varchar
  org_id: int {constraint: foreign_key}
  created_at: timestamp
}

organizations: {
  shape: sql_table
  id: int {constraint: primary_key}
  name: varchar
}

# Foreign key connection
users.org_id -> organizations.id

# Multiple constraints
users: {
  shape: sql_table
  id: int {constraint: [primary_key; not_null]}
}

UML Class Diagrams

UserService: {
  shape: class

  # Fields: visibility prefix + name: type
  -users: User[]
  +db: Database
  #cache: Cache

  # Methods: visibility + name(params): return
  +getUser(id: string): User
  +createUser(data: UserInput): User
  -validateEmail(email: string): bool
}

Visibility: + public, - private, # protected


Sequence Diagrams

auth_flow: {
  shape: sequence_diagram

  # Actors are auto-created on first reference
  # but explicit order controls visual position
  client
  gateway
  auth_service
  db

  client -> gateway: "POST /login"
  gateway -> auth_service: "validate(credentials)"
  auth_service -> db: "SELECT user WHERE email=?"
  db -> auth_service: "user record"
  auth_service -> gateway: "JWT token"
  gateway -> client: "200 OK + token"

  # Notes (standalone shape on actor with no connections)
  auth_service."validates password hash"

  # Groups / fragments
  retry: {
    gateway -> auth_service: "retry"
  }
}

Icons

# Icon from URL (Terrastruct's free icon library)
server: {
  icon: https://icons.terrastruct.com/tech/server.svg
}

# Local file
logo: {
  icon: ./assets/logo.png
}

# Standalone image shape
github: {
  shape: image
  icon: https://icons.terrastruct.com/social/github.svg
}

# Control icon position
server: {
  icon: https://icons.terrastruct.com/tech/server.svg
  icon.near: top-left
}

Free icons: https://icons.terrastruct.com


Composition: Layers, Scenarios, Steps

# Layers: independent views (no inheritance)
layers: {
  overview: {
    web -> app -> db
  }
  detailed: {
    web: "Nginx" { shape: rectangle }
    web -> app: "HTTP/1.1"
    app -> db: "PostgreSQL wire protocol"
  }
}

# Scenarios: variations on base diagram
web -> app -> db

scenarios: {
  with_cache: {
    app -> cache: "read-through"
  }
  with_cdn: {
    cdn -> web
  }
}

# Steps: sequential, each inherits previous
steps: {
  s1: { user }
  s2: { user -> web }
  s3: { user -> web -> app }
  s4: { user -> web -> app -> db }
}

Themes

Set via CLI: d2 --theme=0 input.d2 output.svg Or in-file: vars: { d2-config: { theme-id: 300 } }

IDNameCharacter
0Neutral DefaultClean, professional
1Neutral GreyMuted, monochrome
3Flagship TerrastructVibrant, colorful
4Cool ClassicsBlues and greens
8Colorblind ClearAccessible palette
200Dark MauveDark mode
300TerminalMonospace, hacky
302OrigamiPaper aesthetic
303C4Architecture style

Theme overrides (fine-tune colors):

vars: {
  d2-config: {
    theme-overrides: {
      B1: "#0057b8"    # primary brand color
      N7: "#1a1a2e"    # darkest neutral
    }
  }
}

Color codes: N1N7 (neutrals), B1B6 (brand), AA2AA5 (accent A), AB4AB5 (accent B)


Layouts

Set via CLI: d2 --layout=elk input.d2 output.svg Or in-file: vars: { d2-config: { layout-engine: elk } }

EngineBest ForNotes
dagreEverything — use this alwaysFast, handles nested containers and cross-container connections well
elkOnly if user explicitly requests itExtremely slow in WASM (minutes per render). Do not choose it yourself.

Default rule: never set layout-engine at all. Dagre is the default and handles the vast majority of diagrams well, including nested containers and cross-container connections. Only set layout-engine: elk if the user specifically asks for it.

Direction control:

direction: right    # top-level: up, down, left, right

# ELK supports per-container direction
container: {
  direction: right
  a -> b -> c
}

Imports

# Spread file contents into current scope
...@shared_styles.d2

# Assign file to a key
network: @network_diagram.d2

# Import specific object from file
db_schema: @schema.users

Beautiful Diagram Patterns

Architecture Diagram

# Global style
*.style.border-radius: 6
*.style.font-size: 13

direction: right

internet: {
  shape: cloud
  label: "Internet"
}

frontend: {
  label: "Frontend\n(React)"
  icon: https://icons.terrastruct.com/dev/react.svg
  style.fill: "#e8f4fd"
}

api: {
  label: "API Gateway"
  style.fill: "#fff3cd"
}

services: {
  label: "Microservices"
  style.fill: "#f8f9fa"

  auth: "Auth Service"
  orders: "Orders Service"
  payments: "Payments Service"
}

db: {
  shape: cylinder
  label: "PostgreSQL"
  style.fill: "#d4edda"
}

cache: {
  shape: queue
  label: "Redis"
  style.fill: "#fce8e6"
}

internet -> frontend
frontend -> api: "HTTPS"
api -> services.auth: "JWT validate"
api -> services.orders
api -> services.payments
services.orders -> db
services.payments -> db
services.auth -> cache: "session"

Flowchart

direction: down

start: {shape: circle; style.fill: "#4caf50"; style.font-color: white}
end: {shape: circle; style.fill: "#f44336"; style.font-color: white; label: "End"}
decision: {shape: diamond; label: "Valid?"}
process: "Process Request"
error: "Return Error"

start -> process
process -> decision
decision -> end: "Yes"
decision -> error: "No"
error -> start: "Retry"

ER Diagram

users: {
  shape: sql_table
  id: uuid {constraint: primary_key}
  email: varchar(255) {constraint: [unique; not_null]}
  name: varchar(100)
  created_at: timestamptz
}

posts: {
  shape: sql_table
  id: uuid {constraint: primary_key}
  author_id: uuid {constraint: foreign_key}
  title: varchar(255)
  body: text
  published_at: timestamptz
}

comments: {
  shape: sql_table
  id: uuid {constraint: primary_key}
  post_id: uuid {constraint: foreign_key}
  author_id: uuid {constraint: foreign_key}
  body: text
}

posts.author_id -> users.id
comments.post_id -> posts.id
comments.author_id -> users.id

Saving Rendered SVGs

Always make two d2_render calls and save three files:

Step 1 — Render for saving (full SVG with embedded fonts, for browser viewing):

d2_render(d2_code=..., skip_fonts=false)

Save this output as diagrams/<stem>.svg

Step 2 — Render for display (fonts stripped, compact for LLM context):

d2_render(d2_code=..., skip_fonts=true)

Use this output to show the diagram in the conversation.

Convention:

  • Directory: diagrams/ (relative to the current project root; create if it doesn't exist)
  • Filename stem: YYYY-MM-DD_HH-MM_<slug>
    • Timestamp uses local time in 24-hour format
    • Slug is 2–4 words derived from the diagram's subject, lowercase, hyphenated
    • Example stem: 2025-02-20_14-32_auth-flow-sequence
    • Example stem: 2025-02-20_09-05_aws-three-tier-architecture
    • Example stem: 2025-02-20_17-45_users-orders-er-diagram

Save two files with the same stem:

  1. diagrams/<stem>.d2 — the D2 source code (use the Write tool)
  2. diagrams/<stem>.svg — the full SVG from Step 1 (use the Write tool)

After saving, tell the user both paths so they can edit the source or open the SVG in a browser.

SVG files open directly in any browser and are fully interactive (tooltips, links, animations).


Quick Tips

  • Keys vs Labels: The key is the identifier (my_shape); the label is the display text (my_shape: "Display Text"). Connections use keys, not labels.
  • Semicolons separate multiple declarations on one line: a; b; c or a -> b -> c
  • Repeated connections each create a new arrow — D2 does not merge them
  • _ (underscore) refers to the parent container, useful for cross-container connections
  • near keyword positions shapes or icons relative to constants: top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, bottom-right
  • SVG class attributes are written from D2's class property, enabling CSS/JS post-processing
  • Animated connections (style.animated: true) create flowing arrows in SVG output
  • Use style.multiple: true for a "stacked documents" visual effect
  • SQL tables: stroke styles the body, fill styles the header
  • Avoid width/height on containers with dagre — use elk for that feature

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

Workspace Init

Use this skill to initialize or update a multi-repo workspace created from dev-config-template. Invoke whenever the user wants to: set up a fresh workspace c...

Registry SourceRecently Updated
Coding

Google Seo Assistant

A client-facing SEO assistant grounded in Google's official SEO Starter Guide. Use this skill whenever a user mentions SEO, search rankings, Google visibilit...

Registry SourceRecently Updated
Coding

Version Drift

One command to check if your entire stack is up to date. SSHes into servers, queries APIs, and compares installed versions against latest — across every serv...

Registry SourceRecently Updated