Skip to main content

C4 Architecture Diagrams — Complete Reference

Load this file when the user requests C4 diagrams or system architecture documentation. The C4 model provides four levels of abstraction.

CRITICAL: Mandatory Rules

Every C4 diagram MUST follow these rules. Without them, Mermaid renders harsh black lines that overlap elements and make the diagram unreadable.
  1. Max 6 Rel() per diagram. More relationships cause Dagre to route arrows through nodes, creating unreadable spaghetti. Split complex systems into multiple focused diagrams.
  2. Always style all relationships. Apply UpdateRelStyle to every Rel() with soft line colors (see template below).
  3. Max 6-8 elements per diagram. Tree-shaped topology (1 in, 1-2 out per node) renders best. Avoid mesh connections.
  4. Do NOT set fontFamily. Mermaid’s default font works everywhere. Setting system-ui or Segoe UI will render as Times New Roman in headless Chromium.

Template: Add This to Every C4 Diagram

    %% === MANDATORY: Apply to ALL Rel() references ===
    UpdateRelStyle(fromAlias, toAlias, $textColor="#475569", $lineColor="#94a3b8")
    %% Repeat for each relationship in the diagram

    %% === MANDATORY: Layout optimization ===
    UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")

When Labels Overlap Elements

Add $offsetX and $offsetY to push labels away from elements:
    UpdateRelStyle(from, to, $textColor="#475569", $lineColor="#94a3b8", $offsetY="-10")
    UpdateRelStyle(from, to, $textColor="#475569", $lineColor="#94a3b8", $offsetX="-40", $offsetY="20")

Highlighting Important Relationships

Use accent colors for critical paths while keeping other lines soft:
    %% Primary relationship — emphasized
    UpdateRelStyle(client, api, $textColor="#1e40af", $lineColor="#3b82f6")

    %% Secondary relationships — soft
    UpdateRelStyle(api, db, $textColor="#475569", $lineColor="#94a3b8")

    %% External/risky connection — warning
    UpdateRelStyle(api, extPayment, $textColor="#92400e", $lineColor="#f59e0b")

C4 Levels — When to Use Each

LevelDiagramAudiencePurpose
1C4ContextEveryoneSystem boundaries and external actors
2C4ContainerTechnical teamApplications, databases, services
3C4ComponentDevelopersInternal module structure
4C4DeploymentDevOps/SREInfrastructure and deployment nodes
C4DynamicTechnical teamNumbered request flows
Rule of thumb: Context + Container diagrams are sufficient for most teams. Only create Component/Code diagrams when they genuinely add clarity.

Audience-Appropriate Recommendations

  • Executives/PMs: Context only
  • Architects: Context + Container
  • Developers: Context + Container + Components for their area
  • DevOps/SRE: Container + Deployment

Element Syntax

People and Systems

Person(alias, "Label", "Description")
Person_Ext(alias, "Label", "Description")
System(alias, "Label", "Description")
System_Ext(alias, "Label", "Description")
SystemDb(alias, "Label", "Description")
SystemDb_Ext(alias, "Label", "Description")
SystemQueue(alias, "Label", "Description")
SystemQueue_Ext(alias, "Label", "Description")

Containers

Container(alias, "Label", "Technology", "Description")
Container_Ext(alias, "Label", "Technology", "Description")
ContainerDb(alias, "Label", "Technology", "Description")
ContainerDb_Ext(alias, "Label", "Technology", "Description")
ContainerQueue(alias, "Label", "Technology", "Description")
ContainerQueue_Ext(alias, "Label", "Technology", "Description")

Components

Component(alias, "Label", "Technology", "Description")
Component_Ext(alias, "Label", "Technology", "Description")
ComponentDb(alias, "Label", "Technology", "Description")
ComponentQueue(alias, "Label", "Technology", "Description")

Boundaries

Enterprise_Boundary(alias, "Label") { ... }
System_Boundary(alias, "Label") { ... }
Container_Boundary(alias, "Label") { ... }
Boundary(alias, "Label", "type") { ... }

Relationships

Rel(from, to, "Label")
Rel(from, to, "Label", "Technology")
BiRel(from, to, "Label")
Rel_U(from, to, "Label")       %% Upward
Rel_D(from, to, "Label")       %% Downward
Rel_L(from, to, "Label")       %% Leftward
Rel_R(from, to, "Label")       %% Rightward
Rel_Back(from, to, "Label")    %% Back relationship
Layout control tip: When auto-layout causes lines to overlap, use directional variants (Rel_D, Rel_R, etc.) to force arrows in a specific direction. This is the most effective way to avoid overlapping lines.

Deployment Nodes

Deployment_Node(alias, "Label", "Type") { ... }
Deployment_Node(alias, "Label", "Type", "Description") { ... }
Node(alias, "Label") { ... }
Node_L(alias, "Label") { ... }
Node_R(alias, "Label") { ... }

Complete Examples (All With Mandatory Styling)

Level 1 — System Context

Level 2 — Container

Keep container diagrams focused: max 6-8 elements and 6 Rel(). For complex systems, split into multiple diagrams (one per bounded context or service area).

Level 3 — Component (Order Service)

C4 Dynamic — Request Flow

C4 Deployment

Styling and Layout

Layout Configuration

UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")

Element Styling

UpdateElementStyle(alias, $fontColor="red", $bgColor="grey", $borderColor="red")

Relationship Styling

Use $offsetX and $offsetY to fix overlapping labels:
UpdateRelStyle(from, to, $textColor="#475569", $lineColor="#94a3b8", $offsetY="-10")

Professional Color Palette for Custom Element Styles

PurposebgColorfontColorborderColorWhen to use
Primary emphasis#4f46e5#ffffff#3730a3Core systems, main service
Success / Data store#059669#ffffff#047857Databases, completed states
Warning / External#d97706#ffffff#b45309External systems, risky paths
Error / Critical#dc2626#ffffff#b91c1cError states ONLY
Neutral / Secondary#64748b#ffffff#475569Supporting services, background
Info / Highlight#0284c7#ffffff#0369a1Informational annotations

Microservices Patterns

Single-Team Ownership

When one team owns all services, model each as a container:

Multi-Team Ownership

When separate teams own services, promote them to systems:

Event-Driven Architecture

Show individual topics/queues as containers — NOT a single “Kafka” box:

Essential Rules

  1. Every element must have: Name, Type, Technology (where applicable), Description
  2. Use unidirectional arrows — bidirectional creates ambiguity
  3. Label arrows with action verbs — “Sends email using”, not just “uses”
  4. Include technology labels — “JSON/HTTPS”, “SQL”, “gRPC”
  5. Under 15 elements per diagram — split if more (elegance > completeness)
  6. Always include a title
  7. Meaningful aliasesorderService not s1
  8. ALWAYS add UpdateRelStyle — soft line colors are mandatory
  9. ALWAYS add UpdateLayoutConfig — prevents element crowding

Common Mistakes

MistakeWhy it’s wrongFix
Shared lib as ContainerContainers are deployable unitsModel as Component
Single “Kafka” containerHides topic structureShow individual topics
”Subcomponents” levelNot a C4 conceptUse Component or Class
Removing type labelsLoses informationAlways show type/tech
Bidirectional arrowsAmbiguous flow directionUse unidirectional
No technology labelsCan’t assess architectureAdd protocol/tech
No UpdateRelStyleHarsh black linesAdd soft colors to ALL relationships
No UpdateLayoutConfigElements crowd togetherAdd layout config at end
No offset on overlapLabels hidden behind elementsAdd offsetX/offsetX/offsetY to fix

File Naming Convention

docs/architecture/
├── c4-context.md
├── c4-containers.md
├── c4-components-{feature}.md
├── c4-deployment.md
└── c4-dynamic-{flow}.md