Skip to main content

C4 Model: Practical Software Architecture Design Principles

Constantin Potapov
35 min

Deep dive into C4 model — a framework for architecture visualization that actually works. From context to code, with real examples, diagrams, and mistakes I made. How to document architecture so people read and understand it.

C4 Model: Practical Software Architecture Design Principles

The Problem Everyone Ignores

Let's be honest: nobody reads architectural documentation. It becomes outdated within a week, lives in Confluence as a monument to the past, and newcomers learn through "can I ask you something?". Diagrams turn into art objects — beautiful but useless.

In 15 years, I've seen hundreds of architectural diagrams. The problem isn't that they don't exist. The problem is they don't work. They're either too abstract ("boxes and arrows about nothing") or too detailed ("where's the actual architecture?").

C4 model by Simon Brown solves this elegantly: four levels of abstraction, like Google Maps. You can look at a city from bird's-eye view or zoom into a specific street. Each level answers its own question and is useful for its audience.

I've been using C4 in all projects since 2019. It's not a panacea, but I haven't found a better tool for architecture visualization.

TL;DR: Who Should Read and Why

This article provides different value for different roles. Here's what you'll find:

👨‍💻 Developer (Junior → Middle)

Read: Level 1-3, Practical Rules, Common Pitfalls Why: Understand system structure, where to put new code, how to read architecture diagrams Time: 10 minutes Benefit: Cut onboarding from 3 weeks to 3 days, stop fearing the "big picture"

🏗️ Architect / Tech Lead

Read: Everything + CJM+C4 section, Advanced Techniques, Automation Why: Learn to design architecture the whole team understands, connect UX with technical decisions Time: 30 minutes Benefits:

  • Speed up architectural decisions from 5 days to 1 day
  • Get a framework for connecting CJM and architecture
  • Learn to automate documentation

💼 CTO / Engineering Manager

Read: TL;DR, ROI metrics, Real Cases, Implementation Checklist Why: Get numbers and process for implementing architectural discipline Time: 15 minutes Benefits:

  • −87% onboarding time for new developers
  • −80% errors due to architecture misunderstanding
  • −75% documentation time (through automation)
  • Architecture transparency for all stakeholders

🎨 Product Manager / UX Designer

Read: C4 + CJM section, Level 1-2 Why: Understand how your user journeys translate to technical architecture Time: 15 minutes Benefit: Learn to validate CJM through technical implementation, find gaps between promises and capabilities


Quick Start: If You Only Have 1 Hour for C4

No time to read the whole article? Here's the express plan.

5 Must-Do Things (60 minutes)

1. Create file docs/architecture/system-context.md (10 min)

# Architecture: System Context
 
## Our System
 
[Your product name] — [one sentence, what it does]
 
## Users
 
- **[Role 1]**: [what they do]
- **[Role 2]**: [what they do]
 
## External Systems
 
- **[System 1]**: [why we integrate]
- **[System 2]**: [why we integrate]
 
## Diagram
 
[Draw in Mermaid or paste screenshot from whiteboard]

2. Draw Level 1 on whiteboard/Miro (15 min)

  • One box — your system
  • Stick figures — user roles
  • Boxes — external systems
  • Arrows with labels: who talks to whom

3. Create Level 2: Containers (20 min)

  • What applications/services do you have?
  • Databases, queues, caches
  • How are they connected?

Use Mermaid Live Editor — paste text, get diagram.

4. Add technologies in square brackets (5 min)

  • Web App [React + Next.js]
  • API [Python + FastAPI]
  • Database [PostgreSQL 15]

5. Put in main repository README.md (10 min)

## Architecture
 
See [docs/architecture/system-context.md](docs/architecture/system-context.md)
 
**Quick overview:**
 
- Level 1 (Context): [link to diagram]
- Level 2 (Containers): [link to diagram]

Congratulations! You have basic architectural documentation. This is enough for 80% of tasks. Everything else — as needed.

3 Deadly Sins (What NOT to Do)

Sin #1: Draw diagrams in PowerPoint/draw.io or store in Confluence/Wiki

  • Why bad: impossible to version with code, becomes outdated in a week
  • What to do: Only Diagrams as Code in Git repository. Mermaid, PlantUML, Structurizr DSL
  • Rule: If diagram isn't in same repo as code — it's already outdated

Sin #2: Make diagrams "for the sake of it" and store separately

  • Why bad: nobody will use them, team doesn't even know they exist
  • What to do:
    • Store in project root: /docs/architecture/
    • Link from README.md as first link
    • Present at every onboarding
    • Update in same PR as code

Sin #3: Draw Level 3-4 for everything at start

  • Why bad: waste of time, details will become outdated, team will lose trust
  • What to do: Level 1-2 first, Level 3 — only for complex parts as needed

3 Arguments to Convince Your Team

For developers: "Newcomers will ramp up in 3 days instead of 3 weeks. Fewer 'how does this work?' questions"

For managers: "1,735% ROI in first year. Pays off in a month. Here's the table with numbers [link to ROI section]"

For CTO: "Architecture transparency for investors, auditors, partners. One glance — whole picture"


What is C4 Model

C4 stands for Context, Containers, Components, Code — four levels of abstraction for describing software system architectures.

C4 Philosophy

Key idea: architecture as a map with different zoom levels.

  • Level 1 (Context): Airplane view — system surrounded by users and other systems
  • Level 2 (Containers): City view — what major parts the system consists of
  • Level 3 (Components): Street view — what each part consists of
  • Level 4 (Code): Building blueprint — classes, interfaces, structures

The term "Container" here is not about Docker. Container is a separately deployable/runnable unit: web application, mobile app, database, microservice, message queue.

Principles That Make C4 Work

  1. Abstraction through scale — each level is useful on its own
  2. Audience and purpose — diagrams for people, not for beauty
  3. Evolution over static — diagrams should update like code
  4. Minimalism — only important things, no information noise
  5. Consistent notation — same symbols across all levels

Personal Opinion: IDEF-0 and Déjà Vu Feeling

Honestly, when I first saw C4, I had a strange déjà vu feeling. I remembered IDEF-0 (Integration Definition for Function Modeling) — a functional modeling methodology popular in the 90s and 2000s. I always liked IDEF-0 for its structure and rigor: hierarchical decomposition, inputs-outputs-mechanisms-controls, sequential detailing levels.

C4 is essentially reinventing the wheel. The idea of multi-level abstraction isn't new: IDEF-0 did this 40 years ago, UML Component Diagrams — 25 years ago, Kruchten's 4+1 Architectural View Model — also not born yesterday.

But! This déjà vu doesn't diminish C4's advantages. Why did C4 succeed where IDEF-0 remained niche?

  1. Easy entry: IDEF-0 required training and certification, C4 can be learned in an hour
  2. Modern context: cloud, microservices, DevOps — C4 speaks today's language
  3. Diagrams as Code: IDEF-0 was drawn in specialized editors, C4 lives in Git
  4. Pragmatism vs formalism: C4 doesn't require IDEF-0's strictness, it's more flexible and friendly

So yes, C4 is new packaging of old ideas. But sometimes packaging determines whether a tool gets used or gathers dust in system analysis textbooks.

Comparison Table: C4 vs Other Methodologies

To understand how C4 differs from competitors, here's an honest comparison:

CriteriaC4 ModelArchiMateUML ComponentIDEF-04+1 View Model
Learning curve1-2 hours1-2 weeks2-3 days3-5 days1-2 days
Notation simplicity⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
For DevOps/CI/CDExcellentMediumPoorPoorMedium
AutomationHighLowMediumLowMedium
Diagrams as CodeYes (DSL)PartialYes (PlantUML)NoPartial
Microservices supportExcellentGoodMediumPoorGood
Enterprise adoptionGrowingStandardExistsHistoricalNiche
ToolingМногоFree & paid optionsMediumOutdatedFew
Active communityYesNicheLargeDeadNo
Suitable for startups⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Suitable for enterprise⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Implementation costLowHighMediumMediumLow
Years of existencesince 2014since 2009since 1997since 1981since 1995

When to choose C4:

  • Need quick start (startup, MVP)
  • Team wants simplicity and practicality
  • Have or plan microservices
  • Want Diagrams as Code in Git
  • Need CI/CD integration

When to choose ArchiMate:

  • Enterprise with strict standards
  • Need certification and compliance
  • Describing not just IT but business processes
  • Ready to learn complex notation (free Archi available, paid Sparx Enterprise Architect, BiZZdesign)

When to choose UML:

  • Describing object-oriented system
  • Need detailed class diagrams
  • Team already knows UML
  • Academic environment / education

When to choose IDEF-0:

  • Government project with GOST requirement
  • Describing production processes
  • Need strict formalization
  • Have legacy company standards

When to choose 4+1:

  • Need different views for different stakeholders
  • Complex system with many aspects
  • Combining with other notations

My choice: C4 for 90% of projects. ArchiMate — only in enterprise with strict compliance requirements. UML — for detailing classes in critical components. IDEF-0 — if client requires by contract. 4+1 — never, C4 covers same needs simpler.

Level 1: System Context — Bird's-Eye View

Why Needed

Context diagram answers questions:

  • Who uses the system?
  • What external systems does it interact with?
  • What are the responsibility boundaries?

Audience: everyone — from business to developers.

What to Include

  • Your system (one box)
  • Users (roles, not specific people)
  • External systems (payments, CRM, email services)
  • Interactions (who talks to whom and why)

Example: Online Learning Platform

Practical Rules

What works: - One box for your system, even if 50 microservices inside - User roles, not "manager Vasya" - Verbs on arrows: "sends order", not just "uses"

Anti-patterns:

  • ❌ Inflating Context to Containers level — "let's show databases here"
  • ❌ Showing internal structure — that's Level 2
  • ❌ Technical protocol details — not here

Level 2: Container Diagram — Architectural Zoning

Why Needed

Container diagram reveals the system's major building blocks:

  • What applications/services does the system consist of?
  • How do they interact?
  • What technologies are used?

Audience: architects, tech leads, DevOps, senior developers.

What to Include

  • Web applications (SPA, MPA)
  • Mobile applications (iOS, Android)
  • Backend services (API, workers)
  • Databases (SQL, NoSQL, caches)
  • Message queues (Kafka, RabbitMQ)
  • External systems (from Level 1)

Example: Same Learning Platform

Practical Rules

What to show:

  • Technology stack in labels: API Gateway [Kong]
  • Interaction protocols: HTTP/REST, gRPC, GraphQL, AMQP
  • Replicated databases as separate containers (if important)

Grouping principles:

  • If can be deployed separately — it's a Container
  • If scales independently — it's a Container
  • If has its own CI/CD pipeline — definitely a Container

Common mistake: showing all microservices on one diagram. If you have 40 services — group by domains or make several Level 2 diagrams for different parts.

Why Specify Technologies

This isn't academic pedantry. Technologies on Container diagram:

  • Help newcomers understand project stack in 30 seconds
  • Reveal the zoo — if you have 7 programming languages, maybe time to think?
  • Simplify estimation — architect immediately sees integration complexity

Level 3: Component Diagram — Container Internals

Why Needed

Component diagram shows structure of one Container:

  • What modules/components inside?
  • What responsibilities does each have?
  • How do they interact?

Audience: developers, tech leads, architects (for detailed design).

What to Include

  • Components — logical modules with clear responsibilities
  • Interfaces — public APIs of components
  • Dependencies — who depends on whom
  • External dependencies — databases, queues, other containers

Example: Course Service Internals

Practical Rules

What is Component in C4:

  • Group of related functions/classes with clear responsibility
  • Has public interface (API)
  • Can be replaced with alternative implementation

Component examples:

  • Controllers (MVC)
  • Services / Use Cases
  • Repositories / Data Access
  • Gateways / Adapters
  • Middleware / Interceptors

Tip: Component diagrams aren't mandatory for all containers. Draw them only for complex services where architecture is non-obvious. For simple CRUD API, Level 2 is enough.

Level 3 Anti-patterns

Too detailed: showing every class — that's Level 4 ❌ Too abstract: "Business Logic" as one box — useless ❌ Mixing layers: UI components and business logic at same abstraction level

Right granularity: 5–12 components per diagram. Less — combine, more — decompose Container or group components.

Level 4: Code — Implementation Details

Why Needed (spoiler: often not needed)

Code diagrams show classes, interfaces, data structures. This is UML class diagrams.

Problem: these diagrams become outdated faster than you can draw them.

C4 solution: use auto-generation tools (PlantUML, Structurizr, IDE plugins) or replace Code diagrams with good README in the module.

When Level 4 is Useful

  • Complex design patterns (Strategy, Visitor, Builder)
  • Public APIs of libraries
  • Critical business logic with non-obvious connections

Example (simplified)

Honestly: I draw Code diagrams by hand once a quarter when explaining complex business logic in whiteboard sessions. In repositories they don't live — become outdated instantly.


Practical Principles of C4 Application

Theory is good, but it's nothing without combat experience. Here are key principles that have proven themselves in practice.

1. Diagrams as Code

The ONLY way to keep documentation current is the "Architecture as Code" approach.

Traditional approaches (drawings in Confluence, diagrams in Figma) are doomed from the start. They become outdated within 2-3 weeks and no one updates them.

Write diagrams as text:

Mermaid (simple, built into GitLab/GitHub):

PlantUML (more powerful, requires plugin):

@startuml
!include C4_Context.puml
 
Person(user, "User")
System(platform, "Platform")
System_Ext(payment, "Payment")
 
Rel(user, platform, "Uses")
@enduml

Structurizr DSL (most powerful, for large systems):

workspace {
  model {
    user = person "User"
    platform = softwareSystem "Learning Platform"
    payment = softwareSystem "Payment System"

    user -> platform "Studies on"
    platform -> payment "Processes payments"
  }
  views {
    systemContext platform {
      include *
      autolayout lr
    }
  }
}

Why this is the only working approach:

  1. Version control — diagrams in Git next to code
  2. Review — changes go through PR with discussion
  3. Automation — can generate from code, test in CI/CD
  4. Synchronization — one source of truth for code and docs
  5. Search — full-text search works (try finding something in PNG)

My choice: Mermaid for simple cases (renders directly in GitLab/GitHub), PlantUML for complex systems, Structurizr DSL for enterprises.

2. Store diagrams next to code

Anti-pattern:

  • Diagrams in Confluence
  • Docs in separate repository
  • Drawings in Google Drive
  • "Architecture portal" on SharePoint

Practical approach:

project/
  docs/
    architecture/
      00-overview.md        # System Context
      01-containers.md      # Container diagram
      02-auth-service.md    # Components of Auth Service
    adr/                    # Architecture Decision Records
      001-use-postgres.md
      002-use-event-sourcing.md
  src/
    auth-service/
      README.md             # Links to docs/architecture/02-auth-service.md

Why it works:

  1. Proximity — developers see docs in the repository
  2. Review — changes to architecture go through code review
  3. Relevance — updating a service = updating its docs in the same PR
  4. Onboarding — new team members immediately see the structure

In 10 years, I have NEVER seen current architecture documentation in Confluence/Wiki.

It always turns into an "abandoned cemetery" of outdated diagrams. Documents live only when they're in Git next to the code.

3. Make diagrams "live"

Level 1: Generation from code

Python example:

# services/discovery.py
import yaml
from pathlib import Path
 
def generate_container_diagram():
    """Generate C4 Container diagram from docker-compose.yml"""
 
    with open("docker-compose.yml") as f:
        compose = yaml.safe_load(f)
 
    mermaid = ["graph TB"]
 
    for service, config in compose["services"].items():
        image = config.get("image", "unknown")
        mermaid.append(f'  {service}["{service}<br/>{image}"]')
 
    # Dependencies from environment variables
    for service, config in compose["services"].items():
        env = config.get("environment", {})
        for key, value in env.items():
            if "DATABASE" in key:
                mermaid.append(f"  {service} --> postgres")
            elif "REDIS" in key:
                mermaid.append(f"  {service} --> redis")
 
    return "\n".join(mermaid)
 
if __name__ == "__main__":
    diagram = generate_container_diagram()
    Path("docs/architecture/01-containers.md").write_text(
        f"# Container Diagram\n\n```mermaid\n{diagram}\n```"
    )

Level 2: Testing for synchronization

# tests/test_architecture_sync.py
import pytest
import yaml
import re
 
def test_all_services_documented_in_c4():
    """Check that all services from docker-compose are in C4 diagrams"""
 
    # Read actual services
    with open("docker-compose.yml") as f:
        compose = yaml.safe_load(f)
        actual_services = set(compose["services"].keys())
 
    # Read documented services from C4
    with open("docs/architecture/01-containers.md") as f:
        content = f.read()
        # Find all service mentions in Mermaid diagrams
        documented_services = set(
            re.findall(r'(\w+)\["', content)
        )
 
    missing = actual_services - documented_services
    assert not missing, f"Services not documented: {missing}"
 
def test_all_databases_have_backups():
    """Check that all stateful services have backup configuration"""
 
    with open("docker-compose.yml") as f:
        compose = yaml.safe_load(f)
 
    stateful = {"postgres", "redis", "mongodb"}
 
    for service in stateful:
        if service in compose["services"]:
            volumes = compose["services"][service].get("volumes", [])
            assert any("backup" in v for v in volumes), \
                f"{service} has no backup volume"

Level 3: CI/CD automation

# .gitlab-ci.yml
architecture-check:
  stage: test
  script:
    - python services/discovery.py # Generate diagram
    - git diff --exit-code docs/architecture/ # Check for changes
    # If there are changes - fail the pipeline
  only:
    changes:
      - docker-compose.yml
      - kubernetes/*.yaml

This ensures:

  • Forgot to update C4 when adding a new service → pipeline fails
  • Added a database without backups → tests fail
  • Changed infrastructure → diagram auto-updates

4. Legend and conventions

Each diagram should have a legend so everyone interprets it the same way:

Legend:
  [Blue box] — internal service (we own it)
  [Gray box] — external system (third-party)
  [Red border] — contains PII (personal data)
  [Dashed line] — asynchronous communication (message queue)
  [Solid line] — synchronous (HTTP/gRPC)
  [Lock icon] — requires authentication

Example with color coding:

5. Audience and depth

System Context (Level 1): For everyone (CEO, investors, clients)

  • No technical details
  • Business terminology
  • "What does the system do?"

Containers (Level 2): For architects and tech leads

  • General technology stack
  • Integration points
  • "What are the main moving parts?"

Components (Level 3): For development teams

  • Internal structure of services
  • Design patterns
  • "How is it organized inside?"

Code (Level 4): For developers working with a specific module

  • Classes, interfaces
  • Critical algorithms
  • "How exactly does it work?"

Practical rule: If the diagram doesn't fit on one screen (or one printed A4 page) — you've gone too deep. Split into multiple diagrams.

6. Updates and relevance

When to update C4:

Always:

  • Added a new service/component
  • Changed data flow
  • Integrated with an external system
  • Changed authentication/authorization
  • Migrated to a new technology

⚠️ Sometimes:

  • Refactored code inside a component (if it didn't change interfaces)
  • Updated a library version (if it didn't change architecture)
  • Fixed a bug (if it didn't change structure)

Never:

  • Changed HTML markup
  • Updated text on a page
  • Changed CSS styles

Automation:

# Git hook to remind about documentation
# .git/hooks/pre-commit
 
#!/bin/bash
if git diff --cached --name-only | grep -q "docker-compose.yml"; then
  echo "⚠️  You changed docker-compose.yml"
  echo "   Don't forget to update docs/architecture/01-containers.md"
  echo ""
  read -p "Architecture documentation updated? (y/n) " -n 1 -r
  echo
  if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    exit 1
  fi
fi

Common Pitfalls: 10 Antipatterns I've Encountered

Let me share the mistakes I've made and seen in real projects. Learning from others' mistakes is cheaper than from your own.

1. "C4 as religion"

Symptom: Everything must be strictly according to Simon Brown, any deviation is heresy.

Problem:

  • Spend 2 weeks creating "perfect" Level 4 diagrams for CRUD
  • Force the team to use Structurizr when 90% of cases are covered by Mermaid
  • Create 47 diagrams that no one looks at

Solution: Use C4 as a tool, not a goal. If a component is simple — a paragraph of text is enough. Diagrams are needed where they save time, not where they "should be".

I once insisted on a complete set of C4 diagrams for a startup with 3 people. We spent a month on documentation instead of product. The startup died. The documentation was beautiful.

2. "Illusion of clarity"

Symptom: Beautiful diagrams, but everyone understands them differently.

Problem:

  • No legend — everyone interprets colors and arrows in their own way
  • No description — the diagram is "self-documenting" (spoiler: it's not)
  • No context — unclear what level of abstraction this is

Example of a bad diagram:

What is this? Services? Functions? Teams? No one knows.

Solution:

3. "Architecture for a checkbox"

Symptom: C4 is created for an audit/certification, not for work.

Problem:

  • Created once, never updated
  • Stored in a separate repository/wiki
  • No one knows it exists

Real case:

Client hired me for a "C4 audit". They had 127 (!) PlantUML files. I asked: "When was this last updated?"

Answer: "Two years ago, for ISO certification."

I checked the current codebase — 60% of the services from the diagrams no longer existed, 40% of the new ones weren't documented.

Solution:

Architecture documentation lives only when it's:

  1. In the repository next to the code
  2. Updated in the same PR as the code
  3. Tested in CI/CD (auto-generation or consistency tests)

4. "Premature detailing"

Symptom: Start with Level 4 (code) instead of Level 1 (context).

Problem:

  • Spend a week drawing class diagrams
  • No one understands how the system works as a whole
  • When the architecture changes, all diagrams go in the trash

Real case:

A team came to me: "We have 300 PlantUML diagrams, but new developers still don't understand the system."

I looked — all diagrams were Level 3-4 (components and classes). There wasn't a single Level 1 (System Context).

Solution:

Always start from the top:

  1. Level 1 — who uses the system, what external systems are there
  2. Level 2 — what are the main parts of the system
  3. Level 3 — how complex services are structured
  4. Level 4 — only for the most critical/complex components

5. "Forgot about security"

Symptom: The diagram doesn't show which components handle sensitive data.

Problem:

  • Can't conduct a security audit
  • Unclear where to apply encryption
  • Difficult to assess GDPR/PII compliance

Example of a diagram without security:

All services look the same, but the database contains PII.

Solution:

Immediately visible:

  • DB contains sensitive data (red border)
  • API requires authentication (🔐)
  • All connections are encrypted

6. "Diagrams live separately from reality"

Symptom: The diagram shows version 1.0, production is running version 3.5.

Problem:

  • No automation — diagrams are drawn manually
  • No checks — no one verifies synchronization with code
  • No culture — no one updates docs

Real case:

Client: "We have Container diagrams in Confluence."

Me: "When was it updated?"

Client: "Last year when we started the project."

Me: "How many services do you have now?"

Client: "23."

Me: "The diagram shows 7."

Solution:

Approach 1: Generation from code

# Auto-generate diagram from docker-compose.yml
python scripts/generate_c4_from_compose.py > docs/01-containers.md

Approach 2: Integration testing

def test_all_services_documented_in_c4():
    """Check that all services from docker-compose are in C4"""
 
    # Read actual services from docker-compose.yml
    with open("docker-compose.yml") as f:
        compose = yaml.safe_load(f)
        actual = set(compose["services"].keys())
 
    # Read documented services from C4 Container diagram
    with open("docs/architecture/01-containers.md") as f:
        content = f.read()
        # Extract service names from Mermaid diagram
        documented = set(re.findall(r'(\w+)\["', content))
 
    # If a service exists but isn't documented - test fails
    missing = actual - documented
    assert not missing, f"Services not in C4: {missing}"

Approach 3: CI/CD checks

# .gitlab-ci.yml
test-architecture-sync:
  script:
    - pytest tests/test_architecture_sync.py
  only:
    changes:
      - docker-compose.yml
      - kubernetes/*.yaml

7. "Everything in one diagram"

Symptom: One giant diagram with 50+ elements.

Problem:

  • Doesn't fit on screen
  • Can't understand anything
  • Can't print

Example of a bad diagram:

[Giant diagram with 50 boxes, 100 arrows,
 font size 6px, no one can read it]

Solution:

Split into multiple focused diagrams:

docs/architecture/
  01-context.md                    # System Context (all external systems)
  02-containers.md                 # All containers of the system
  03-auth-service-components.md   # Auth Service components
  04-course-service-components.md # Course Service components
  05-payment-flow.md              # Payment scenario (dynamic)
  06-deployment-prod.md           # Deployment diagram

Each diagram — one screen, one topic.

8. "No one knows what level this is"

Symptom: Mixing different abstraction levels in one diagram.

Problem:

This mixes:

  • Level 1 (User — external actor)
  • Level 2 (WebApp, API — containers)
  • Level 3 (AuthController — component)
  • Level 4 (bcrypt.hash — code)

Solution:

Each diagram — one level:

Level 2: Containers

Level 3: Auth Service components

9. "Technology instead of purpose"

Symptom: The diagram shows "PostgreSQL", "Redis", "Kafka", but it's unclear what they're for.

Bad:

What's stored in Postgres? Why is Redis needed? What does Kafka do?

Good:

Now it's clear:

  • Postgres — long-term data storage
  • Redis — temporary session cache
  • Kafka — asynchronous event exchange

10. "Forgot about operations"

Symptom: The diagram shows functional components, but doesn't show how it all works in production.

Problem:

  • Unclear how deployment happens
  • No monitoring/logging
  • No disaster recovery strategy

Solution:

Add a Deployment diagram (C4 extension):

Now visible:

  • How many API instances (3 pods)
  • Databases have replication (Multi-AZ)
  • There's monitoring (Prometheus + Grafana)
  • Everything is in Kubernetes

Key rule: If you recognize yourself in these antipatterns — good! Recognizing a problem is the first step to solving it.

Real Cases: C4 in Action

Theory is good, but practice is better. Here are three real stories from my consulting experience (company names changed for confidentiality).

Case 1: "Microservice Chaos" — Fintech Startup

Problem:

Fintech startup, 25 microservices, 15 developers. New team members couldn't understand the system architecture for 3 weeks. Each asked: "Where does the payment flow go?", "Which service is responsible for KYC?", "Why do we have 3 databases?"

No one could answer. The tech lead left 4 months ago, taking the knowledge with him.

What we did:

Week 1: Created Level 1 (System Context)

Result: Everyone understood "what the system does as a whole" in 30 minutes.

Week 2: Created Level 2 (Containers)

Mapped all 25 microservices to business capabilities:

Result: Payment flow became obvious, team leads could distribute tasks by services.

Week 3-4: Created Level 3 for critical services

Example for Payment Service:

Results:

3 weeks → 3 days
Onboarding time
0
"Which service is responsible?" questions
100%
Developers understand the architecture

Business effect:

  • Saved ~$45,000 on onboarding (15 days × 5 developers × $200/hour)
  • Reduced time to make architecture decisions by 80%
  • Found 3 duplicate services (were doing the same thing)

Case 2: "Legacy Monolith" — E-commerce Company

Problem:

E-commerce company, 10 years old monolith in PHP. 300,000 lines of code. No one knows what depends on what. Any change is like playing Russian roulette.

Question: "Can we separate catalog into a separate service?"

Answer: "We don't know, we need to investigate for 2 weeks."

What we did:

Step 1: Reverse engineering — created Container diagram from code

Wrote a Python script:

import re
from pathlib import Path
 
def analyze_dependencies():
    """Analyze dependencies between modules"""
 
    modules = {}
 
    for file in Path("src").rglob("*.php"):
        content = file.read_text()
 
        # Find module name
        module = file.parent.name
 
        # Find dependencies (use/require)
        deps = re.findall(r'use\s+App\\(\w+)', content)
 
        if module not in modules:
            modules[module] = set()
        modules[module].update(deps)
 
    return modules
 
def generate_c4_container(modules):
    """Generate C4 Container diagram"""
 
    mermaid = ["graph TB"]
 
    for module, deps in modules.items():
        mermaid.append(f'  {module}["{module}"]')
        for dep in deps:
            mermaid.append(f'  {module} --> {dep}')
 
    return "\n".join(mermaid)

Result: Got a diagram with REAL dependencies:

Key discovery: Circular dependency between Order and Payment!

Step 2: Created Component diagrams for the most complex modules

For the Order module:

Step 3: Created a separation plan

Based on C4, created a roadmap:

  1. Break circular dependency Order ↔ Payment
  2. Separate Auth into a service (no dependencies on it)
  3. Separate Catalog (depends only on Product, Inventory, Pricing)
  4. Separate Payment (depends on User, publishes events)
  5. Separate Order (depends on Payment, Catalog, Shipping)

Results:

2 weeks → 2 hours
Architecture analysis
6 months
Monolith → microservices migration
3x
Development speed increase

Business effect:

  • Saved ~$80,000 on investigation (2 weeks × 4 senior devs × $200/hour)
  • Reduced deployment time from 2 hours to 15 minutes
  • Decreased number of production incidents by 60%

Case 3: "Documentation Graveyard" — Enterprise

Problem:

Large bank, 200+ services, 50 teams. Architecture documentation exists, but:

  • 80% is outdated
  • Stored in Confluence (500+ pages)
  • No one updates it
  • New developers don't read it (because it's irrelevant)

What we did:

Step 1: Migrated to "Architecture as Code"

Created structure in Git:

architecture/
  00-system-context.md       # Level 1: System Context
  01-containers.md           # Level 2: All services
  domains/
    payments/
      02-payment-flow.md     # Level 3: Payment components
      03-fraud-detection.md  # Level 3: Fraud components
    lending/
      02-loan-origination.md
      03-credit-scoring.md

Step 2: Set up auto-generation from Kubernetes

# scripts/generate_c4_from_k8s.py
import yaml
from kubernetes import client, config
 
def generate_container_diagram():
    """Generate C4 Container from Kubernetes deployments"""
 
    config.load_kube_config()
    v1 = client.AppsV1Api()
 
    deployments = v1.list_deployment_for_all_namespaces()
 
    mermaid = ["graph TB"]
 
    for dep in deployments.items:
        name = dep.metadata.name
        namespace = dep.metadata.namespace
 
        # Group by domain (namespace)
        mermaid.append(f'  subgraph "{namespace}"')
        mermaid.append(f'    {name}["{name}"]')
        mermaid.append(f'  end')
 
    return "\n".join(mermaid)

Step 3: Set up CI/CD checks

# .gitlab-ci.yml
architecture-sync:
  stage: test
  script:
    - python scripts/generate_c4_from_k8s.py > architecture/01-containers-actual.md
    - diff architecture/01-containers.md architecture/01-containers-actual.md
  only:
    changes:
      - kubernetes/**/*

Results:

500 pages → 50 diagrams
Documentation reduction
80% outdated → 100% current
Relevance
0%
Manual maintenance

Business effect:

  • Saved ~$200,000/year on documentation maintenance
  • Onboarding time reduced from 3 weeks to 5 days
  • Architecture decisions are made 5x faster

ROI: Numbers That Matter

Based on my experience implementing C4 in 15+ companies:

Time Savings

MetricBefore C4After C4Change
New developer onboarding18-21 days3-5 days−87%
Architecture decision time3-7 days0.5-1 day−80%
Time to find service owner2-4 hours2-5 minutes−95%
Integration understanding1-2 days1-2 hours−90%

Quality Improvements

MetricBefore C4After C4Change
Architecture errors in PRs15-20%2-4%−85%
Production incidents12/month3/month−75%
"Architecture not considered" issues30%5%−83%
Documentation outdatedness80%<10%−90%

Financial Effect

Investment (for a team of 20 developers):

  • Initial implementation: 40 hours ($8,000)
  • Maintenance: 2 hours/week ($4,000/year)
  • Total first year: $12,000

Savings (conservative estimate):

  • Onboarding: 15 days × 5 developers × $200/hour = $60,000/year
  • Reduced incidents: 9 incidents × 4 hours × 5 people × $200/hour = $36,000/year
  • Faster decisions: 100 decisions × 3 days × $200/hour = $120,000/year
  • Total savings: $216,000/year

ROI = ($216,000 − $12,000) / $12,000 × 100% = 1,700%

Real case: One of my clients calculated ROI for C4 at 1,735% in the first year. The main effect was reduced onboarding time and fewer production incidents.

Intangible Benefits

What's hard to measure but incredibly valuable:

  • Architectural thinking — developers start thinking at the system level
  • Common language — everyone speaks the same terms
  • Confidence — team knows the system will scale
  • Transparency — management sees what's actually being built
  • Knowledge transfer — knowledge doesn't leave with departing employees

Tools and Ecosystem

C4 is not tied to specific tools. You can draw diagrams in anything. But some tools are more convenient than others.

Level 1: Text-Based (Diagrams as Code)

Mermaid ⭐ My choice for 80% of cases

Pros:

  • Works out of the box in GitLab/GitHub/Notion
  • Simple syntax
  • No additional tools needed
  • Renders directly in README.md

Cons:

  • Limited styling
  • No auto-layout (you specify positions manually)
  • For complex systems can become unwieldy

When to use: Small/medium projects, startups, internal documentation


PlantUML ⭐ For complex systems

@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
 
Person(user, "User")
System(platform, "Platform")
 
Rel(user, platform, "Uses")
@enduml

Pros:

  • Powerful C4 library (C4-PlantUML)
  • Auto-layout
  • Rich styling
  • Export to PNG/SVG

Cons:

  • Requires PlantUML server or plugin
  • More complex syntax
  • Doesn't render natively in GitHub

When to use: Large systems, enterprises, when you need perfect diagrams


Structurizr DSL ⭐ For large enterprises

workspace {
  model {
    user = person "User"
    platform = softwareSystem "Platform"

    user -> platform "Uses"
  }
  views {
    systemContext platform {
      include *
      autolayout lr
    }
  }
}

Pros:

  • Most powerful (from C4 creator Simon Brown)
  • One model — many views
  • Version control and collaboration
  • Integration with Structurizr cloud

Cons:

  • Steep learning curve
  • Requires Structurizr CLI or cloud
  • Overkill for small projects

When to use: 50+ services, multiple teams, strict governance

Level 2: Visual Tools

draw.io (diagrams.net) — for quick sketches

Pros:

  • Free
  • Works in browser
  • Export to PNG/SVG
  • Integration with Google Drive/Confluence

Cons:

  • Not "diagrams as code"
  • Manual maintenance
  • Difficult to version control

When to use: Prototyping, presentations, one-time diagrams


Lucidchart — for collaboration

Pros:

  • Real-time collaboration
  • Ready-made C4 templates
  • Integration with Jira/Confluence

Cons:

  • Paid ($7.95/month)
  • Not "diagrams as code"
  • Vendor lock-in

When to use: Non-technical stakeholders, workshops

Level 3: Platform Solutions

Structurizr Cloud — SaaS for C4

Pros:

  • Official solution from C4 creator
  • Version control
  • Multiple workspaces
  • Access control

Cons:

  • Paid (from $7.50/month)
  • Vendor lock-in

When to use: Enterprises with budget, strict access control requirements


IcePanel — modern C4 platform

Pros:

  • Beautiful diagrams
  • Collaboration
  • Integration with CI/CD
  • Landscape view (all services on one screen)

Cons:

  • Paid (from $12/user/month)
  • New tool (may have rough edges)

When to use: Startups willing to invest in architecture documentation

My Recommendations

For startups (1-5 people):

  • Mermaid in README.md
  • No additional tools
  • Cost: $0

For small companies (5-20 people):

  • Mermaid for simple diagrams
  • PlantUML for complex ones
  • Store in docs/architecture/ in Git
  • Cost: $0

For medium companies (20-100 people):

  • PlantUML + C4-PlantUML
  • CI/CD auto-generation from code
  • Integration testing for synchronization
  • Cost: $0 (only developer time)

For enterprises (100+ people):

  • Structurizr DSL + Structurizr Cloud
  • Or IcePanel for modern UI
  • Strict governance and access control
  • Cost: $750-1,200/month (for 100 users)

My stack: Mermaid for 80% of cases, PlantUML when I need perfect auto-layout, Structurizr DSL for clients with 50+ services.


Implementation Checklist

Ready to implement C4 in your project? Here's a step-by-step checklist.

Week 1: Foundation

  • Choose a tool

    • Small project → Mermaid
    • Medium → PlantUML
    • Large → Structurizr DSL
  • Create structure in Git

    docs/
      architecture/
        00-overview.md
        01-system-context.md
        02-containers.md
        README.md
    
  • Create Level 1: System Context

    • Who are the users?
    • What external systems exist?
    • What are the main boundaries?
  • Show to the team, gather feedback

Week 2: Detailing

  • Create Level 2: Containers

    • List all services/applications
    • Show data flows
    • Mark critical dependencies
  • Add legend

    • Color scheme
    • Arrow notation
    • Technology icons
  • Document deployment

    • Where does it run? (Cloud/on-prem)
    • How many instances?
    • Which databases?

Week 3: Critical Components

  • Choose 2-3 most complex services

  • Create Level 3: Components for them

    • Internal structure
    • Interaction between modules
    • Patterns (CQRS, Event Sourcing, etc.)
  • Document ADRs (Architecture Decision Records)

    • Why this technology?
    • What alternatives were considered?
    • What are the consequences?

Week 4: Automation

  • Set up auto-generation (if possible)

    # Generate from docker-compose.yml
    python scripts/generate_c4.py
  • Add tests for synchronization

    def test_all_services_in_c4():
        actual = get_services_from_compose()
        documented = get_services_from_c4()
        assert actual == documented
  • Set up CI/CD

    test-architecture:
      script:
        - pytest tests/test_architecture_sync.py

Ongoing: Culture

  • Update rule: Changed architecture → update diagram in the same PR

  • Code review: Check that diagrams match code

  • Onboarding: New employee's first task — read C4, ask questions

  • Retro: Every quarter — review relevance of diagrams

Key rule: C4 is not a one-time task, it's a process. Documents live when they're part of development culture.


How C4 Combines with Other Practices

C4 doesn't exist in a vacuum. It's a part of the architecture ecosystem.

C4 + Event Storming

Event Storming — workshop method for discovering business processes and domain events.

How they complement each other:

  1. Event Storming → identify domains and bounded contexts
  2. C4 Level 1 → show domains as systems
  3. C4 Level 2 → show services inside each domain
  4. Event Storming → define events between services
  5. C4 dynamic diagrams → show event flows

Example:

After Event Storming we identified:

  • Domain: "Orders"
  • Events: OrderCreated, OrderPaid, OrderShipped

In C4:

C4 + ADR (Architecture Decision Records)

ADR — markdown documents with architecture decisions.

How they complement each other:

  • C4 — shows "what" (which services exist)
  • ADR — explains "why" (why we chose this)

Example:

C4 Container diagram:

ADR-005: Use PostgreSQL for Event Store

# ADR-005: Use PostgreSQL for Event Store
 
## Status: Accepted
 
## Context
 
We need to store events for Event Sourcing.
Considered: EventStoreDB, PostgreSQL, Kafka.
 
## Decision
 
Use PostgreSQL with jsonb for events.
 
## Consequences
 
- Team already knows PostgreSQL
- No need to learn new tool
- Simpler operations (backup, monitoring)
  − Lower performance than specialized EventStoreDB
  − Manual implementation of projections
 
## Alternatives Considered
 
1. EventStoreDB — specialized, but new tool
2. Kafka — designed for streaming, not storage

C4 + Domain-Driven Design (DDD)

DDD — methodology for modeling complex domains.

How they complement each other:

  • DDD — defines bounded contexts and aggregates
  • C4 — visualizes them

Example:

DDD: Bounded contexts: Orders, Payments, Shipping

C4 Level 2:

DDD: Aggregate Order with entities OrderLine, Discount

C4 Level 3:

C4 + Kubernetes

How they complement each other:

  • C4 Level 2 — logical services
  • C4 Deployment diagram — how they're deployed in Kubernetes

Example:

Level 2: Containers (logical)

Deployment (Kubernetes)

C4 + Customer Journey Map (CJM)

CJM — customer journey through product.

How they complement each other:

  • CJM — business view (what the user does)
  • C4 — technical view (which services support this)

Mapping matrix:

CJM StageUser Pain PointC4 ContainerC4 ComponentTechnical SolutionSuccess Metric
DiscoveryHard to find coursesWeb App + Search ServiceSearchEngine, MLRecommenderML recommendationsCTR >15%
RegistrationLong, complex formAuth ServiceRegistrationFlow, SocialAuthOAuth (Google, GitHub)Conversion >60%
PurchaseConcerns about payment securityPayment ServicePaymentGateway, FraudDetectionPCI DSS, 3D SecureAbandonment <5%
LearningVideo bufferingVideo Service + CDNVideoStreaming, AdaptiveBitrateHLS, CDN edge cacheStart time <2s
CompletionNo certificate receivedCertificate ServiceCertificateGenerator, EmailSenderPDF generation, SMTPDelivery >99.9%

Example:

CJM: User watches a course (stage: "Learning")

C4 dynamic diagram:


Advanced Techniques

When you've mastered the basics, here are some advanced techniques.

1. Color Coding for Risk Zones

Use colors to highlight critical/risky system components.

Legend:

  • 🔵 Blue — standard services
  • 🟠 Orange — critical for business (payment)
  • 🔴 Red border — contains sensitive data (PII, PCI DSS)
  • ⚪ Gray dashed — external services (third-party)

2. Deployment Diagrams for Different Environments

Show how architecture changes across environments.

Production:

Staging:

Development:

3. Dynamic Diagrams for Scenarios

Static diagrams show structure, dynamic ones show behavior.

Scenario: User purchases a course

4. Context Maps for Microservices

Show relationships between team domains (from DDD).

Legend:

  • 🟢 Green — Upstream (publishes interface)
  • 🟡 Yellow — Downstream (consumes interface)
  • 🟠 Orange — Conformist (adapts to any changes)

5. Landscape View for Platforms

When you have 50+ services — group by domain.


My Mistakes with C4 (2019-2025)

I've been using C4 for 6 years. Here are 5 major mistakes I've made.

Mistake #1: "Documentation for Documentation's Sake" (2019)

What I did:

First project with C4. I was excited. Created:

  • Level 1: System Context ✅
  • Level 2: 15 containers ✅
  • Level 3: 47 component diagrams ✅
  • Level 4: 128 class diagrams ✅

Total: 190 diagrams.

Result:

  • Spent 3 months on documentation
  • No one read it
  • After 2 months it became outdated
  • Team continued to code without C4

Lesson:

Start small. Level 1-2 is enough for 90% of cases. Level 3-4 — only for the most critical/complex components.

Rule: If a diagram hasn't been viewed in 3 months — delete it. Documentation must be living, not a museum.

Mistake #2: "Wrong Tool for the Team" (2020)

What I did:

Implemented Structurizr DSL for a startup of 5 people.

Rationale: "We'll scale to 100 services, need a professional tool!"

Result:

  • Spent 2 weeks learning DSL
  • Team didn't understand the syntax
  • Local Structurizr Lite constantly broke
  • Ended up going back to Mermaid

Lesson:

Choose a tool based on current needs, not future ones. Mermaid is enough for 80% of projects.

Rule: Startup (5-20 people) → Mermaid. Company (20-100 people) → PlantUML. Enterprise (100+ people) → Structurizr DSL.

Mistake #3: "Perfect Diagrams, Dead Documentation" (2021)

What I did:

Created beautiful C4 diagrams in PlantUML. Spent a week tweaking colors, icons, layout.

Stored them in a separate architecture repository.

Result:

  • Diagrams looked amazing (could show at a conference)
  • But developers didn't update them
  • After 3 months — 50% of services not documented
  • Diagrams were perfect, but useless

Lesson:

Diagrams should live in the same repository as the code. "Architecture as Code" — or death.

Rule: If diagrams are not in Git next to the code — they will die. Always. No exceptions.

Mistake #4: "Forgot About Business" (2022)

What I did:

Created C4 for a client. Detailed Level 2-3, all containers and components.

Showed to the CTO — he was delighted.

Then the CEO asked: "And what value does this bring to customers?"

I couldn't answer.

Result:

Realized I described the technical structure but didn't connect it to business value.

Lesson:

Every service in C4 should have a business justification:

Rule: Level 1 (System Context) should be understandable to the CEO. If not — you did it wrong.

Mistake #5: "Ignored Operations" (2023-2024)

What I did:

Created C4 Level 1-3 for a client. All services, components, data flows.

Launched in production.

At 3 AM received a call: "Everything is down, where's the monitoring?"

Looked at C4 — no observability, no monitoring, no disaster recovery plan.

Result:

C4 showed the "happy path", but not failure scenarios.

Lesson:

Add operational aspects to C4:

Now visible:

  • What monitoring exists (Prometheus + Grafana)
  • Where logs are stored (Loki)
  • How distributed tracing works (Tempo)
  • How alerts work (PagerDuty)

Rule: If your C4 doesn't show monitoring/logging/alerting — you're not ready for production.


Conclusion from mistakes: C4 is a tool, not a goal. Use it to solve real problems, not to create perfect diagrams.


Implementation Plan: Week by Week

Ready to implement C4 in your team? Here's a detailed plan.

Week 1: Foundation and Context

Goals:

  • Choose a tool
  • Create Level 1 (System Context)
  • Get team buy-in

Action Plan:

Monday:

  • Team meeting: introduce C4 concept (30 minutes)
  • Choose tool (Mermaid/PlantUML/Structurizr DSL)
  • Create docs/architecture/ structure in repository

Tuesday-Wednesday:

  • Create Level 1: System Context
  • Identify all users (User, Admin, Support, etc.)
  • Identify all external systems (payment systems, APIs, email, etc.)
  • Draw boundaries of your system

Thursday:

  • Team review of System Context
  • Gather feedback and correct
  • Add legend and description

Friday:

  • Publish System Context to main branch
  • Announce in team chat
  • Ask everyone to read and comment

Deliverable: 1 System Context diagram understandable to the CEO


Week 2: Containers and Dependencies

Goals:

  • Create Level 2 (Containers)
  • Document all services and dependencies
  • Identify integration points

Action Plan:

Monday:

  • List all services/applications (from docker-compose/k8s/etc.)
  • Group by layer (frontend, backend, data)
  • Identify main data flows

Tuesday-Wednesday:

  • Create Level 2: Container diagram
  • Add all services
  • Draw connections (HTTP, gRPC, message queues, etc.)
  • Mark databases and caches

Thursday:

  • Add color coding:
    • Internal services — blue
    • External systems — gray
    • Databases with PII — red border
  • Add legend
  • Document technologies (Node.js, PostgreSQL, Redis, etc.)

Friday:

  • Team review
  • Correct based on feedback
  • Publish to main

Deliverable: 1 Container diagram with all services and dependencies


Week 3: Critical Components

Goals:

  • Create Level 3 (Components) for 2-3 most complex services
  • Document architecture patterns
  • Connect C4 to code

Action Plan:

Monday:

  • Team vote: which services are most complex/critical?
  • Select 2-3 services for Level 3
  • For each service: list main components

Tuesday-Wednesday:

  • Create Level 3 diagrams for selected services
  • Show internal structure (controllers, services, repositories)
  • Document patterns (CQRS, Event Sourcing, Saga, etc.)
  • Add links to code (src/auth-service/README.md → docs/architecture/03-auth-components.md)

Thursday:

  • Create ADRs (Architecture Decision Records) for key decisions
    • Why PostgreSQL and not MongoDB?
    • Why Event Sourcing and not CRUD?
    • Why Kafka and not RabbitMQ?

Friday:

  • Team review
  • Publish to main
  • Add C4 links to service READMEs

Deliverable: 2-3 Component diagrams + 3-5 ADRs


Week 4: Automation and Testing

Goals:

  • Set up auto-generation (if possible)
  • Add tests for synchronization
  • Integrate into CI/CD

Action Plan:

Monday-Tuesday:

  • Write script for diagram generation from code
    • From docker-compose.yml → Container diagram
    • From kubernetes/*.yaml → Deployment diagram
    • From OpenAPI spec → API integrations

Wednesday:

  • Write integration tests:
    def test_all_services_documented():
        actual = get_services_from_docker_compose()
        documented = get_services_from_c4()
        assert actual == documented

Thursday:

  • Set up CI/CD:
    architecture-check:
      script:
        - python scripts/generate_c4.py
        - git diff --exit-code docs/architecture/
        - pytest tests/test_architecture_sync.py

Friday:

  • Test on real PR (change docker-compose → CI should fail)
  • Document update process in README
  • Retro: what worked, what didn't?

Deliverable: Automated checks in CI/CD, tests for synchronization


Month 2-3: Embedment and Culture

Ongoing Actions:

Every PR with architecture changes:

  • Update C4 in the same PR
  • Code review checks diagram relevance
  • CI/CD verifies synchronization

Every month:

  • Architectural review:
    • Are diagrams current?
    • Are there new services not in C4?
    • Can we remove outdated diagrams?

Every new employee:

  • Onboarding task: read C4, ask questions
  • After 2 weeks: update C4 (fix inaccuracies found)

Every quarter:

  • Architectural retro:
    • Did C4 help in the last 3 months?
    • What's missing?
    • What should be removed?

Key: C4 is not a project, it's a process. Documents live when they're part of development culture, not a one-time task.


Conclusion

C4 Model is a practical framework that actually works. Not just beautiful slides, but a working tool that:

  • Reduces onboarding time from 3 weeks to 3 days
  • Speeds up architecture decisions by 5x
  • Decreases production incidents by 75%
  • Returns 1,700% ROI in the first year

Key principles:

  1. Start simple — Level 1-2 is enough for 90% of cases
  2. Architecture as Code — diagrams in Git or they'll die
  3. Automation — generate from code, test in CI/CD
  4. Culture — documents live when they're part of the process

When C4 works:

✅ Growing team (5+ people)
✅ Microservices/complex system
✅ High onboarding cost
✅ Frequent architecture decisions
✅ Need for transparent architecture

When C4 is overkill:

❌ Landing page on Next.js
❌ Solo developer
❌ Project for 2 weeks
❌ Legacy CRUD with no changes

Next Steps:

  1. Read official C4 documentation
  2. Choose a tool (Mermaid for start)
  3. Create System Context (1 hour)
  4. Show to team, gather feedback
  5. Iterate and improve

My experience: I've implemented C4 in 15+ projects. It doesn't work everywhere, but when it does — it radically changes how the team understands the system.


Changelog

Version 1.1 (2025-12-13)

Added:

  • TL;DR section for different roles (Developer, Architect, CTO, PM)
  • Quick Start "I don't have time to read" section
  • Expanded antipatterns from 5 to 10
  • Comparison table of methodologies (C4 vs ArchiMate vs UML vs IDEF-0 vs 4+1)
  • Detailed CJM→C4 mapping matrix with metrics
  • ROI section with real numbers (−87% onboarding, 1,735% ROI)
  • "My mistakes with C4" section (2019-2025, 5 major errors)
  • Week-by-week implementation plan
  • Advanced techniques (color coding, deployment diagrams, dynamic diagrams)
  • Practical examples for all 4 C4 levels

Improved:

  • Enhanced "Architecture as Code" emphasis throughout article
  • Added integration testing examples
  • Expanded Tools and Ecosystem section
  • Added How C4 Combines with Other Practices section
  • More real-world case studies with metrics

Fixed:

  • ArchiMate tooling description (clarified free vs paid tools)
  • Integration testing example made more concrete
  • Quick Start section moved to beginning of article
  • Added ADR explanation

Version 1.0 (Initial)

  • Basic C4 Model overview
  • 4 levels of abstraction
  • Basic practical principles
  • 5 antipatterns
  • Initial comparison with IDEF-0