Simon Brown introduced the C4 model in 2018 as a response to a very specific frustration: architecture diagrams that neither developers nor stakeholders could read, because they tried to show everything at once. C4 does not solve diagramming. It solves the abstraction problem — by giving you a framework for choosing what to show to whom.
If you have spent any time as a solution architect you have drawn dozens of what C4 would call "mystery diagrams" — boxes with unlabelled arrows, missing technology labels, no clear system boundary. C4 is the discipline that stops you drawing those.
The Four Levels
Level 1: System Context
The highest level of abstraction. Your system is a single box in the centre. Around it are the people (actors) who use it and the external systems it interacts with. No technology. No internal structure. Just: what is this system, who uses it, and what does it depend on?
This diagram is for everyone — business stakeholders, product managers, security reviewers, new engineers. It fits on a single slide. It should be the first diagram any new team member encounters.
Level 1: System Context — one box per actor/external system, no internal structure
Level 2: Container
Zoom into your system. Containers are the deployable units: web applications, APIs, databases, message queues, mobile apps. Each container has a technology label (React SPA, Node.js API, PostgreSQL, Kafka) and shows how they communicate.
This diagram is for technical stakeholders — engineering managers, architects, senior engineers on other teams. It answers: how is this system structured, and what technology decisions have been made?
C4Container
title Container Diagram — E-Commerce Platform
Person(customer, "Customer")
System_Boundary(ecommerce, "E-Commerce Platform") {
Container(spa, "Web App", "React / TypeScript", "Single-page application served via CDN")
Container(api, "API Gateway", "Node.js / Express", "Routes requests; handles auth")
Container(catalogue, "Catalogue Service", "Go", "Product search and detail pages")
Container(order, "Order Service", "Python / FastAPI", "Cart, checkout, order lifecycle")
ContainerDb(db, "PostgreSQL", "PostgreSQL 15", "Orders, users, products")
Container(queue, "Event Bus", "Apache Kafka", "Async events between services")
}
System_Ext(payment, "Stripe")
Rel(customer, spa, "Uses", "HTTPS")
Rel(spa, api, "Calls", "HTTPS/JSON")
Rel(api, catalogue, "Routes to", "gRPC")
Rel(api, order, "Routes to", "gRPC")
Rel(order, db, "Reads/writes", "SQL")
Rel(order, queue, "Publishes events", "Kafka protocol")
Rel(order, payment, "Charges via", "HTTPS/API")Level 3: Component
Zoom into a single container to show its internal structure — the major logical components, their responsibilities, and how they interact. This is the level at which you document design patterns: repositories, services, adapters, domain objects.
This diagram is for the team building and maintaining that container. It is too detailed for business stakeholders and too focused for architects reviewing the overall system.
C4Component
title Component Diagram — Order Service
Container_Boundary(order, "Order Service") {
Component(api, "Order API", "FastAPI Router", "HTTP endpoints for cart and checkout")
Component(svc, "Order Domain Service", "Python class", "Business logic: validation, pricing, lifecycle")
Component(repo, "Order Repository", "SQLAlchemy", "Persistence layer; wraps PostgreSQL")
Component(pub, "Event Publisher", "aiokafka", "Publishes OrderPlaced, OrderShipped events")
Component(payAdapter, "Payment Adapter", "httpx client", "Wraps Stripe API; handles retries")
}
ContainerDb(db, "PostgreSQL")
Container_Ext(queue, "Kafka")
System_Ext(stripe, "Stripe")
Rel(api, svc, "Delegates to")
Rel(svc, repo, "Reads/writes via")
Rel(svc, pub, "Emits events via")
Rel(svc, payAdapter, "Charges via")
Rel(repo, db, "SQL")
Rel(pub, queue, "Kafka protocol")
Rel(payAdapter, stripe, "HTTPS/API")Level 4: Code
UML class diagrams, ER diagrams, or similar representations of the actual code structures within a component. In practice, most teams skip this level — modern IDEs generate it on demand, and it goes stale faster than any other level. Reserve it for genuinely complex domain models that benefit from explicit documentation.
The Three Mistakes Most Teams Make
1. Starting at Level 3
The most common mistake is skipping Level 1 and Level 2 entirely and drawing a component diagram as the first (and only) architectural artefact. Level 3 is meaningful only in context. Without a container diagram showing which service you are decomposing, a component diagram is unreadable to anyone outside the immediate team.
Always draw Level 1 first. It takes ten minutes and forces clarity about system boundaries that most teams have never explicitly defined.
2. Ignoring actors
A system context diagram without human actors is an infrastructure diagram. Actors are what give the diagram its purpose: they reveal why the system exists, what it enables, and who is affected by changes. Include not just end-users but also operators, administrators, and downstream consumers of your APIs.
3. Treating C4 as a one-time deliverable
C4 diagrams maintained in a wiki die. C4 diagrams committed to the repository alongside the services they describe live. Adopt the practice of updating the relevant C4 level as part of any pull request that changes a system boundary, adds a new container, or restructures a component's internals.
Practical Adoption Path
Start with a single Level 1 context diagram for your most critical system. Use AI generation to produce the first draft — describe the system in plain English, and let the model produce valid Mermaid C4Context syntax. Review it with your team in thirty minutes. Commit it to the repository. That is day one.
Week two: draw the Level 2 container diagram. Week three: pick one container and draw its Level 3 component diagram. By week four you will have more architectural documentation than most organisations accumulate in a year — and it will be in git, where it belongs.