C4 Model Decision Guidance
Use this skill to determine the appropriate abstraction level and diagram type for software architecture documentation.
Quick Decision Flowchart
START: What are you documenting?
│
├─► External boundaries & users → C4Context (SYSTEM CONTEXT)
│ (Who uses it? What external systems does it integrate with?)
│
├─► Internal technical structure → C4Container (CONTAINER)
│ (What applications/databases make up the system?)
│
├─► Internal component design → C4Component (COMPONENT)
│ (How is a specific container organized internally?)
│ ⚠️ Only if it adds value!
│
├─► Runtime behavior & sequences → C4Dynamic (DYNAMIC)
│ (How do components interact at runtime? What's the flow?)
│
└─► Infrastructure & deployment → C4Deployment (DEPLOYMENT)
(Where does it run? AWS, Azure, Kubernetes, servers?)
All 5 Diagram Types
| Diagram Type | Mermaid Keyword | Purpose | When to Use |
|---|---|---|---|
| System Context | C4Context | Big picture: system, users, external dependencies | Always - starting point for all documentation |
| Container | C4Container | Technical building blocks within a system | Always - shows technology choices |
| Component | C4Component | Internal structure of a single container | Optional - only if it adds value |
| Dynamic | C4Dynamic | Runtime interactions, sequences, flows | When behavior/flow matters more than structure |
| Deployment | C4Deployment | Infrastructure, nodes, where containers run | For ops, DevOps, infrastructure documentation |
Decision by Audience
| Your Audience | Primary Diagrams | Why |
|---|---|---|
| Business stakeholders, non-technical | System Context | Big picture, no jargon |
| Technical team, architects, devs | Container, Component | Technology choices & structure |
| DevOps, operations, SREs | Deployment, Container | Infrastructure & runtime topology |
| Understanding workflows/sequences | Dynamic | Shows runtime behavior |
Core Abstractions
Person
Definition: An actor, role, or persona that interacts with your software system.
Use when: Identifying who uses your system (human users, external systems acting as users).
Examples: Customer, Admin User, Support Staff, External API Consumer
Software System
Definition: The highest level of abstraction. Something that delivers value to users. Typically:
- •Owned by a single team
- •Lives in one repository
- •Deployed as a unit
Use when: Defining the boundary of what you're building and identifying external dependencies.
Decision criteria: If one team owns, builds, and maintains it → it's ONE software system.
NOT a software system: Product domains, bounded contexts, business capabilities, feature teams.
Container
Definition: An application or data store - a runtime boundary around executing code or stored data. NOT a Docker container!
Use when: Showing major technical building blocks and technology choices.
Examples:
- •Server-side apps: Java EE, ASP.NET, Node.js, Rails
- •Client-side apps: React SPA, Angular, mobile apps
- •Databases: PostgreSQL, MongoDB, Redis
- •Storage: S3, Azure Blob
- •Serverless: Lambda functions, Azure Functions
- •Message queues: RabbitMQ, Kafka
Decision criteria:
- •Web app with significant client-side JS? → TWO containers (client + server)
- •Static HTML generator? → ONE container
- •External cloud service you configure (S3, RDS)? → Show as container, not external system
NOT a container: JARs, DLLs, libraries (these organize code within containers).
Component
Definition: A grouping of related functionality behind a well-defined interface. NOT independently deployable - runs in same process as its container.
Use when: You need to show internal structure of a container AND it adds value.
Examples:
- •Controllers (web layer)
- •Services (business logic)
- •Repositories (data access)
- •Modules/packages with clear boundaries
Decision criteria:
- •Does this diagram help understanding? → Create it
- •Will it become stale quickly? → Consider automating generation
- •Is the container simple? → Skip component diagram
NOT a component: Domain/model classes, utilities, helpers (filter these out as noise).
Deployment Node
Definition: Infrastructure where containers run - physical/virtual servers, cloud services, Kubernetes clusters, etc.
Use when: Documenting where and how software is deployed.
Examples:
- •AWS EC2 instances, ECS clusters, Lambda
- •Kubernetes nodes, pods
- •Azure App Service, VMs
- •On-premise servers, data centers
Mermaid C4 Element Reference
Person Elements
Person(alias, "Label", "Description") Person_Ext(alias, "Label", "Description") # External person
System Elements
System(alias, "Label", "Description") System_Ext(alias, "Label", "Description") # External system SystemDb(alias, "Label", "Description") # Database system SystemDb_Ext(alias, "Label", "Description") # External database system SystemQueue(alias, "Label", "Description") # Queue system SystemQueue_Ext(alias, "Label", "Description") # External queue system
Container Elements
Container(alias, "Label", "Technology", "Description") Container_Ext(alias, "Label", "Technology", "Description") ContainerDb(alias, "Label", "Technology", "Description") # Database ContainerDb_Ext(alias, "Label", "Technology", "Description") ContainerQueue(alias, "Label", "Technology", "Description") # Message queue ContainerQueue_Ext(alias, "Label", "Technology", "Description")
Component Elements
Component(alias, "Label", "Technology", "Description") Component_Ext(alias, "Label", "Technology", "Description") ComponentDb(alias, "Label", "Technology", "Description") ComponentDb_Ext(alias, "Label", "Technology", "Description") ComponentQueue(alias, "Label", "Technology", "Description") ComponentQueue_Ext(alias, "Label", "Technology", "Description")
Deployment Elements
Deployment_Node(alias, "Label", "Type", "Description") Node(alias, "Label", "Type", "Description") # Shorthand Node_L(alias, "Label", "Type", "Description") # Left-aligned Node_R(alias, "Label", "Type", "Description") # Right-aligned
Boundary Elements
Boundary(alias, "Label", "Type") { ... }
Enterprise_Boundary(alias, "Label") { ... }
System_Boundary(alias, "Label") { ... }
Container_Boundary(alias, "Label") { ... }
Relationship Elements
Rel(from, to, "Label", "Technology", "Description") BiRel(from, to, "Label", "Technology") # Bidirectional # Directional relationships (for layout control) Rel_Up(from, to, "Label", "Technology") # or Rel_U Rel_Down(from, to, "Label", "Technology") # or Rel_D Rel_Left(from, to, "Label", "Technology") # or Rel_L Rel_Right(from, to, "Label", "Technology") # or Rel_R Rel_Back(from, to, "Label") # Backward direction # For Dynamic diagrams (numbered steps) RelIndex(index, from, to, "Label")
Styling Functions
UpdateElementStyle(elementName, $bgColor="color", $fontColor="color", $borderColor="color") UpdateRelStyle(from, to, $textColor="color", $lineColor="color", $offsetX="num", $offsetY="num") UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="2")
Diagram Examples
1. System Context Diagram (C4Context)
Use for: Big picture overview, stakeholder communication
C4Context
title System Context Diagram - E-Commerce Platform
Person(customer, "Customer", "A user who buys products")
Person(admin, "Admin", "Manages products and orders")
System(ecommerce, "E-Commerce Platform", "Allows customers to browse and purchase products")
System_Ext(payment, "Payment Gateway", "Handles payment processing")
System_Ext(email, "Email Service", "Sends transactional emails")
SystemDb_Ext(analytics, "Analytics Platform", "Tracks user behavior")
Rel(customer, ecommerce, "Browses, purchases")
Rel(admin, ecommerce, "Manages")
Rel(ecommerce, payment, "Processes payments")
Rel(ecommerce, email, "Sends emails")
Rel(ecommerce, analytics, "Sends events")
2. Container Diagram (C4Container)
Use for: Technical architecture, technology choices
C4Container
title Container Diagram - E-Commerce Platform
Person(customer, "Customer", "A user who buys products")
System_Boundary(ecommerce, "E-Commerce Platform") {
Container(web, "Web Application", "React", "Delivers the SPA")
Container(api, "API Server", "Node.js/Express", "Handles business logic")
ContainerDb(db, "Database", "PostgreSQL", "Stores products, orders, users")
ContainerDb(cache, "Cache", "Redis", "Session and product cache")
ContainerQueue(queue, "Message Queue", "RabbitMQ", "Async job processing")
}
System_Ext(payment, "Payment Gateway", "Stripe")
Rel(customer, web, "Uses", "HTTPS")
Rel(web, api, "Calls", "JSON/HTTPS")
Rel(api, db, "Reads/writes", "SQL")
Rel(api, cache, "Reads/writes", "Redis protocol")
Rel(api, queue, "Publishes", "AMQP")
Rel(api, payment, "Processes payments", "HTTPS")
3. Component Diagram (C4Component)
Use for: Internal structure of a container (only if it adds value)
C4Component
title Component Diagram - API Server
Container_Boundary(api, "API Server") {
Component(controllers, "Controllers", "Express Routes", "Handles HTTP requests")
Component(services, "Services", "Business Logic", "Order processing, inventory")
Component(repos, "Repositories", "Data Access", "Database queries")
Component(auth, "Auth Module", "JWT/Passport", "Authentication & authorization")
ComponentQueue(events, "Event Publisher", "EventEmitter", "Publishes domain events")
}
ContainerDb(db, "Database", "PostgreSQL")
ContainerDb_Ext(cache, "Cache", "Redis")
ContainerQueue_Ext(queue, "Message Queue", "RabbitMQ")
Rel(controllers, auth, "Validates tokens")
Rel(controllers, services, "Calls")
Rel(services, repos, "Uses")
Rel(services, events, "Publishes")
Rel(repos, db, "Queries")
Rel(services, cache, "Caches")
Rel(events, queue, "Sends")
4. Dynamic Diagram (C4Dynamic)
Use for: Runtime flows, sequences, use case walkthroughs
C4Dynamic
title Dynamic Diagram - Order Placement Flow
Person(customer, "Customer", "Places an order")
Container(web, "Web App", "React")
Container(api, "API Server", "Node.js")
ContainerDb(db, "Database", "PostgreSQL")
Container_Ext(payment, "Payment Service", "Stripe")
ContainerQueue(queue, "Queue", "RabbitMQ")
Rel(customer, web, "1. Submits order")
Rel(web, api, "2. POST /orders")
Rel(api, db, "3. Save order (pending)")
Rel(api, payment, "4. Process payment")
Rel(payment, api, "5. Payment confirmed")
Rel(api, db, "6. Update order (paid)")
Rel(api, queue, "7. Publish OrderPaid event")
Rel(api, web, "8. Return confirmation")
Rel(web, customer, "9. Show success")
5. Deployment Diagram (C4Deployment)
Use for: Infrastructure, DevOps, where things run
C4Deployment
title Deployment Diagram - AWS Production
Deployment_Node(aws, "AWS", "Cloud Provider") {
Deployment_Node(region, "us-east-1", "AWS Region") {
Deployment_Node(vpc, "VPC", "Network Boundary") {
Deployment_Node(alb, "ALB", "Load Balancer") {
Container(lb, "Load Balancer", "AWS ALB", "Distributes traffic")
}
Deployment_Node(ecs, "ECS Cluster", "Container Orchestration") {
Deployment_Node(service, "API Service", "ECS Service") {
Container(api1, "API Instance 1", "Node.js")
Container(api2, "API Instance 2", "Node.js")
}
}
Deployment_Node(rds, "RDS", "Managed Database") {
ContainerDb(db, "PostgreSQL", "RDS PostgreSQL", "Primary database")
}
Deployment_Node(elasticache, "ElastiCache", "Managed Cache") {
ContainerDb(cache, "Redis", "ElastiCache Redis", "Session cache")
}
}
}
Deployment_Node(cloudfront, "CloudFront", "CDN") {
Container(cdn, "CDN", "CloudFront", "Static assets")
}
Deployment_Node(s3, "S3", "Object Storage") {
Container(static, "Static Assets", "S3 Bucket", "JS, CSS, images")
}
}
Rel(lb, api1, "Routes to")
Rel(lb, api2, "Routes to")
Rel(api1, db, "Reads/writes")
Rel(api2, db, "Reads/writes")
Rel(api1, cache, "Caches")
Rel(api2, cache, "Caches")
Rel(cdn, static, "Serves from")
Anti-Patterns to Avoid
1. Over-diagramming
Problem: Creating all 5 diagram types for every system. Solution: Start with System Context + Container. Add others only when needed.
2. Container vs Component Confusion
Problem: Showing JARs/DLLs/libraries as containers. Solution: Containers are runtime boundaries. Libraries are implementation details within containers.
3. Docker Container Confusion
Problem: Equating C4 containers with Docker containers. Solution: C4 containers are architectural abstractions. A Docker container might host a C4 container, shown in Deployment diagrams.
4. Missing External Systems
Problem: Focusing only on your system, ignoring dependencies.
Solution: Always show external systems (_Ext variants) your software interacts with.
5. Too Much Detail in Context Diagrams
Problem: Including technology choices in System Context. Solution: Keep System Context technology-agnostic. Save tech details for Container level.
6. Stale Component Diagrams
Problem: Hand-maintained component diagrams that drift from code. Solution: Automate component diagram generation, or skip them entirely.
7. Static Diagrams for Dynamic Problems
Problem: Using Container/Component diagrams to explain workflows. Solution: Use Dynamic diagrams (C4Dynamic) for runtime behavior and sequences.
8. Mixing Infrastructure with Architecture
Problem: Showing AWS services in Container diagrams. Solution: Use Deployment diagrams for infrastructure. Container diagrams show logical architecture.
Summary: Default Recommendations
| Diagram | Recommendation | Rationale |
|---|---|---|
| System Context | Always create | Essential for all stakeholders |
| Container | Always create | Essential for technical team |
| Component | Optional | Only if it adds value |
| Dynamic | As needed | When explaining workflows/sequences |
| Deployment | For production systems | Essential for DevOps/operations |
Quick Element Selection Guide
| What you're representing | Use this element |
|---|---|
| Human user | Person / Person_Ext |
| Your software system | System |
| External system you don't control | System_Ext |
| Application within your system | Container |
| Database within your system | ContainerDb |
| Message queue within your system | ContainerQueue |
| External service you integrate with | Container_Ext / ContainerDb_Ext |
| Logical grouping inside a container | Component |
| Server, cloud instance, K8s node | Deployment_Node / Node |
| Numbered step in a flow | RelIndex (Dynamic diagrams only) |