| name | description |
|---|---|
C4 Diagrams |
Creating C4 architecture diagrams using D2 diagram language. Use when creating system context diagrams, container diagrams, component diagrams, code diagrams, deployment diagrams, or any software architecture visualization following the C4 model. Also applies when discussing architecture at different zoom levels or explaining system boundaries. |
Create C4 model diagrams using D2's text-to-diagram syntax. Supports both graphical (SVG/PNG) and ASCII output.
The C4 model provides four levels of zoom for software architecture:
| Level | Audience | Shows | Excludes |
|---|---|---|---|
| Context | Everyone | System + users + external systems | Technologies, internal details |
| Container | Technical | Apps, databases, services | Component internals |
| Component | Developers | Internal modules, responsibilities | Code-level details |
| Code | Developers | Classes, interfaces, functions | Usually auto-generated |
Key principle: "Different levels of zoom for different audiences."
Person → Users, actors, roles
Software System → The system being designed OR external systems
Container → Applications, databases, file stores (deployable units)
Component → Functional groupings within a container
Deployment Node → Physical/virtual infrastructure where containers run
Relationship → Directed connections with descriptions
# Person - use person shape
user: Customer {
shape: person
}
# Software System - rectangle with double border
system: Banking System {
shape: rectangle
style.double-border: true
}
# External System - dashed border
external: Email Provider {
style.stroke-dash: 3
}
# Container - standard rectangle
api: API Application {
shape: rectangle
}
# Database - cylinder shape
db: Database {
shape: cylinder
}
# Component - rectangle (inside container)
auth: Auth Module {
shape: rectangle
}Key rule: Use white text on dark backgrounds, black text on light backgrounds.
# Dark fills with white text (high contrast)
person: User {
style.fill: "#08427b" # Dark navy
style.font-color: "#ffffff"
}
system: Main System {
style.fill: "#1168bd" # Medium blue
style.font-color: "#ffffff"
}
external: External {
style.fill: "#6c757d" # Dark gray (NOT light gray #999)
style.font-color: "#ffffff"
style.stroke-dash: 3
}
container: Container {
style.fill: "#1168bd" # Medium blue
style.font-color: "#ffffff"
}
# Light fills with black text (for code diagrams)
class_box: ClassName {
style.fill: "#cce5ff" # Light blue
style.font-color: "#000000"
}
struct_box: StructName {
style.fill: "#d4edda" # Light green
style.font-color: "#000000"
}
gem_box: ExternalGem {
style.fill: "#ffeeba" # Light yellow
style.font-color: "#000000"
}Contrast guidelines:
- Dark backgrounds (#08427b, #1168bd, #6c757d) → white text (#ffffff)
- Light backgrounds (#cce5ff, #d4edda, #ffeeba, #f0f7ff) → black text (#000000)
- Avoid mid-tone grays (#999999) as they lack contrast with white text
- Container boundaries: use light fill (#f0f7ff) with dark stroke (#1168bd)
Multi-line labels - Use quoted strings with \n:
# Correct - quoted string with newlines
node: MyNode {
label: "Title\n[Technology]\nDescription"
}
# Also correct - markdown block (top-level only)
node: |md
**Title**
[Technology]
Description
|Edge labels with brackets - Quote labels containing [] or /:
# Correct
a -> b: "Makes calls [JSON/HTTPS]"
a -> b: "HTTP GET [Faraday]"
# Incorrect - will fail
a -> b: Makes calls [JSON/HTTPS]Double-border requires shape - Must specify shape: rectangle:
# Correct
system: Name {
shape: rectangle
style.double-border: true
}Nested containers - Use simpler labels inside nested structures:
outer: Container {
inner: Component {
style.fill: "#85bbf0"
label: "Name\n[Tech]\nDescription" # Quoted, not markdown
}
}Purpose: Big picture showing your system in context Audience: Everyone (technical and non-technical)
# System Context Diagram: [System Name]
# Shows the system and its relationships with users and external systems
direction: right
# People
customer: Customer {
shape: person
style.fill: "#08427b"
style.font-color: "#ffffff"
}
admin: Administrator {
shape: person
style.fill: "#08427b"
style.font-color: "#ffffff"
}
# Your System (focus)
system: Internet Banking System {
shape: rectangle
style.fill: "#1168bd"
style.font-color: "#ffffff"
style.double-border: true
}
# External Systems
email: E-mail System {
style.fill: "#999999"
style.font-color: "#ffffff"
style.stroke-dash: 3
}
mainframe: Mainframe Banking System {
style.fill: "#999999"
style.font-color: "#ffffff"
style.stroke-dash: 3
}
# Relationships (describe the interaction, not the mechanism)
customer -> system: "Views account balances, makes payments"
admin -> system: "Manages users and configuration"
system -> email: Sends notifications
system -> mainframe: "Gets account info, makes payments"Include:
- Your software system (center focus)
- Users/personas who interact with it
- External systems it depends on or integrates with
Exclude:
- Technologies, protocols, APIs
- Internal structure
- Deployment details
Purpose: Zoom into the system boundary showing major building blocks Audience: Technical people
# Container Diagram: [System Name]
# Shows the containers (applications, data stores) within the system
direction: down
# External actors (from context)
customer: Customer {
shape: person
style.fill: "#08427b"
style.font-color: "#ffffff"
}
# System boundary
system: Internet Banking System {
style.fill: transparent
style.stroke: "#1168bd"
style.stroke-width: 2
# Web Application
webapp: Web Application {
shape: rectangle
style.fill: "#438dd5"
style.font-color: "#ffffff"
label: |md
**Web Application**
[Java/Spring MVC]
Delivers static content and
the single page application
|
}
# API Application
api: API Application {
shape: rectangle
style.fill: "#438dd5"
style.font-color: "#ffffff"
label: |md
**API Application**
[Java/Spring Boot]
Provides banking functionality
via JSON/HTTPS API
|
}
# Database
db: Database {
shape: cylinder
style.fill: "#438dd5"
style.font-color: "#ffffff"
label: |md
**Database**
[PostgreSQL]
Stores user data, accounts,
transactions
|
}
}
# External systems
email: E-mail System {
style.fill: "#999999"
style.stroke-dash: 3
}
# Relationships with technology/protocol
customer -> system.webapp: Visits using HTTPS
system.webapp -> system.api: Makes API calls to\n[JSON/HTTPS]
system.api -> system.db: Reads/writes\n[JDBC]
system.api -> email: Sends emails using\n[SMTP]Include:
- All containers within the system boundary
- Technology choices (in brackets: [Java/Spring])
- Brief responsibility descriptions
- External systems and people that connect
Exclude:
- Internal component structure
- Deployment topology (clusters, load balancers)
- Code-level details
What counts as a Container:
- Web applications, mobile apps, desktop apps
- Server-side APIs, microservices
- Databases, file systems, blob storage
- Message queues, event streams
- Serverless functions
Purpose: Zoom into a single container showing internal components Audience: Software architects and developers
# Component Diagram: [Container Name]
# Shows the components within this container
direction: right
# The container being decomposed
api: API Application {
style.fill: transparent
style.stroke: "#438dd5"
style.stroke-width: 2
# Controllers
signin: Sign In Controller {
shape: rectangle
style.fill: "#85bbf0"
label: |md
**Sign In Controller**
[Spring MVC Controller]
Allows users to sign in
|
}
accounts: Accounts Controller {
shape: rectangle
style.fill: "#85bbf0"
label: |md
**Accounts Controller**
[Spring MVC Controller]
Provides account information
|
}
# Components
security: Security Component {
shape: rectangle
style.fill: "#85bbf0"
label: |md
**Security Component**
[Spring Security]
Authentication and authorization
|
}
facade: Banking Facade {
shape: rectangle
style.fill: "#85bbf0"
label: |md
**Banking Facade**
[Spring Bean]
Orchestrates banking operations
|
}
# Internal connections
signin -> security: Uses
accounts -> facade: Uses
facade -> security: Uses
}
# External elements this container interacts with
db: Database {
shape: cylinder
style.fill: "#438dd5"
}
mainframe: Mainframe {
style.fill: "#999999"
style.stroke-dash: 3
}
api.facade -> db: Reads/writes\n[JDBC]
api.facade -> mainframe: Makes API calls\n[XML/HTTPS]Use sparingly: Only create if they add value. Consider automating generation.
Include:
- Components within the container boundary
- Technology implementation (in brackets)
- Key responsibilities
- Connected containers and external systems
Purpose: Lowest level showing code structure Recommendation: Usually auto-generate from IDE or skip entirely
# Code Diagram: [Component Name]
# Usually auto-generated - manual creation rarely worthwhile
direction: down
# Classes
controller: AccountsController {
shape: class
+getAccounts(): List<Account>
+getAccount(id): Account
-validateAccess(): boolean
}
service: AccountService {
shape: class
+findAll(): List<Account>
+findById(id): Account
}
repo: AccountRepository {
shape: class
<<interface>>
+findAll(): List<Account>
+findById(id): Account
}
controller -> service: uses
service -> repo: usesFor enterprises with multiple systems:
# System Landscape: [Organization Name]
# Shows all systems and how they relate
direction: right
# People
customer: Customer {
shape: person
}
# Internal Systems
banking: Banking System {
style.double-border: true
}
atm: ATM System {
style.double-border: true
}
# External Systems
credit: Credit Bureau {
style.stroke-dash: 3
}
customer -> banking
customer -> atm
banking -> credit
atm -> banking# Deployment Diagram: [Environment Name]
# Shows infrastructure and container deployment
direction: down
# Cloud region
aws: AWS us-east-1 {
style.fill: "#f5f5f5"
# Availability zone
az1: Availability Zone 1 {
style.fill: "#e8e8e8"
ec2: EC2 Instance {
style.fill: "#d4d4d4"
docker: Docker {
api: API Container {
style.fill: "#438dd5"
}
}
}
}
rds: RDS {
db: PostgreSQL {
shape: cylinder
style.fill: "#438dd5"
}
}
}
aws.az1.docker.api -> aws.rds.db: Reads/writes\n[JDBC/SSL]For runtime behavior (numbered steps):
# Dynamic Diagram: [Use Case Name]
# Shows runtime interactions for a specific scenario
direction: right
user: Customer {
shape: person
}
webapp: Web App
api: API
db: Database {
shape: cylinder
}
user -> webapp: 1. Submits login form
webapp -> api: 2. POST /auth/login
api -> db: 3. SELECT user WHERE email=...
db -> api: 4. Returns user record
api -> webapp: 5. Returns JWT token
webapp -> user: 6. Redirects to dashboard# Describe WHAT and sometimes HOW
user -> webapp: Views account balances using
api -> db: Reads/writes account data\n[JDBC]
api -> email: Sends password reset emails\n[SMTP]# Too vague - don't use single words
user -> system: Uses # Bad
a -> b: Calls # Bad
x -> y: Connects # Bad# SVG (recommended for web/docs)
d2 diagram.d2 diagram.svg
# PNG (for images/presentations)
d2 diagram.d2 diagram.png
# With specific theme
d2 --theme 200 diagram.d2 diagram.svgFor code comments and terminal documentation, use the d2ascii skill:
# ASCII output
d2 diagram.d2 diagram.txt
# Pure ASCII (maximum compatibility)
d2 diagram.d2 diagram.txt --ascii-mode=standardASCII limitations: No colors, no icons, simplified shapes. Keep diagrams simple for ASCII.
- Title stating diagram type and scope
- Key/legend explaining notation (especially colors)
- Element type labels (Person, Software System, Container, Component)
- Technology labels on containers/components (in brackets)
- Meaningful relationship descriptions (not just "uses")
- Protocol/mechanism on technical relationships
| Mistake | Fix |
|---|---|
| Missing diagram title | Add descriptive title at top |
| Vague labels ("Uses", "Calls") | Describe the interaction specifically |
| Missing technology labels | Add [Technology] in brackets |
| Too much detail for the level | Remove details, zoom in with next level |
| No key/legend | Add legend explaining colors/shapes |
| Acronyms without explanation | Define in legend |
Always begin with a System Context diagram:
- Identify your system's boundaries
- List all users/personas
- Identify external system dependencies
For each system, create Container diagram:
- List all deployable units
- Show technology choices
- Map communication paths
Only for complex containers where it adds value:
- Show internal architecture
- Document module responsibilities
- Run through checklist above
- Get feedback from team
- Update as architecture evolves
Shapes:
shape: person- Users/actorsshape: rectangle- Systems, containers, componentsshape: cylinder- Databasesshape: class- Code-level (UML)
Styling:
style.double-border: true- Your system (focus)style.stroke-dash: 3- External systemsstyle.fill: "#color"- Background color
Commands:
d2 input.d2 output.svg- Graphical outputd2 input.d2 output.txt- ASCII outputd2 --theme 200 input.d2 output.svg- With theme
- Create diagrams without titles - Always state type and scope
- Use vague relationship labels - "Uses" tells nothing
- Mix abstraction levels - Each diagram stays at one level
- Show deployment in container diagrams - Use deployment diagrams
- Skip the legend - Colors and shapes need explanation
- Label element types - Person, System, Container, Component
- Include technology choices - [Java/Spring], [PostgreSQL]
- Describe relationships specifically - What data flows, what action
- Show direction - Arrows indicate dependency/data flow direction
- Keep it simple - If diagram is cluttered, zoom in or split