Be Software Architecture Wise
Be Wise Apps

Leer en español · Lire en français · Auf Deutsch lesen

Section 4.3 of 4.8 · Intermediate · 20 min read

The C4 model: context, containers, components and code

Video lesson

5 min · narrated, with captions
Listen only (audio)
Read the transcript

Ask a team to draw its architecture, and you often get unexplained shapes, unlabelled lines and mixed levels of detail. In this lesson you'll learn Simon Brown's answer: the C4 model.

Think of an online map. Zoomed out, you see a whole country and the motorways between cities. Zoom in and you see one city's districts, then one district's streets, then a single building. Each zoom level is useful to different people. And you always know which level you are looking at. C4 does the same for software. It isn't a new notation, but a small set of abstractions and a hierarchy of diagrams.

Level one, the system context diagram, shows your system as a single box, with the people who use it and the other software systems it connects to. It's for everyone, technical or not. Level two, the container diagram, shows the applications and data stores inside the system. C4 recommends these first two levels for every team. Level three, the component diagram, zooms into one container. Draw it only where it adds value, for complex or risky parts. Level four shows the code itself. It's rarely worth drawing by hand, because most tools can generate it on demand.

The word container needs care. In C4, a container is a separately runnable or deployable unit that executes code or stores data: a web app, a mobile app, a service, a database schema or a message topic. It is not the same as a Docker container. A mobile app on a phone is a C4 container, yet it doesn't run in Docker. How many copies of a container run, and where, belongs on a deployment diagram.

Here is level one for the food-delivery platform. Customers, restaurant staff and couriers each have a labelled arrow saying what they do with the platform, which is shown as a single box. Below are the external systems it depends on: a payment provider, a maps service and push services. Seeing at once that these are bought in is architecturally significant.

Now zoom in to level two. For most teams, this container diagram is the most valuable diagram they own. At the top, each kind of user has an app, and each app names its technology. Every app calls the platform's application programming interface, or API, through an API gateway, which authenticates users and routes requests. Notice the protocol on every arrow. The ordering service places orders and takes payment. It reads from and writes to the order database. It also publishes order events to a Kafka topic, drawn as a container in its own right. The dispatch and notification services consume from it. Those arrows are dashed because they are asynchronous, and the key says so. Outside the boundary are the three external systems, and at the bottom is the key. How many copies of each service run is left to a deployment diagram.

C4 doesn't prescribe shapes or colours, but it does prescribe what every diagram must say. Each one needs a title stating its type and scope, and a key that explains every shape and line style. Every element has a name, a type, a one-sentence description and, for containers and components, its technology. Every relationship is one arrow, in one direction, labelled with what it does. Never just uses. Between containers, add the protocol, and show whether it's synchronous or asynchronous. Keep to one level of abstraction: no classes on a container diagram. And use colour only as a supplement, because diagrams get printed in black and white and are read by colour-blind people.

Let's apply the rules. A team shares a whiteboard diagram: five boxes, including App, Backend and DB, lines with no arrowheads, one green box, and no title or key. First, decide what it is. It mixes an app, a service and a database, so it's a container diagram, and it gets a title saying so. Each box gets a name, a type and a technology. App becomes the customer app, and DB becomes the order database. Each plain line becomes one labelled arrow with a protocol. The team discovers one line meant two different things, a call one way and a webhook the other, so it becomes two arrows. Labelling the arrows also exposes a Kafka topic that nobody had drawn. And the green box turns out to mean owned by our team, which goes in the key. The result has more on it, yet needs less explanation, because it answers every question a reader would ask. Most of the value came from labelling the arrows.

The full section adds the component diagram, the supplementary diagrams, and modelling tools. Next, in Section four point four, we look at the parts of the Unified Modeling Language, or UML, that architects still use. See you there.

What you need to know

Maps of your code

The C4 model is an approach to diagramming software architecture created by Simon Brown. It grew out of the software architecture training he gave from around 2006: according to the C4 site, its roots go back to somewhere between 2006 and 2009, the diagram types were named in early 2010 and the name "C4" was first used in early 2011. Brown had noticed that teams asked to draw their architecture produced diagrams that were hard to understand: unexplained shapes and colours, boxes that could be anything from a class to a data centre, unlabelled lines and several levels of detail mixed on one page. UML, which might have solved the problem, had largely fallen out of everyday use.

His answer was not a new notation but a small set of abstractions and a hierarchy of diagrams built on them, which he compares to the zoom levels of an online map. You start with the whole country, zoom into a city, then a district, then a street. Each level shows a different amount of detail for a different purpose, and you always know which level you are looking at. C4 is deliberately notation-independent and tool-independent: you can draw it on a whiteboard, in a drawing tool or with a modelling tool, provided you follow a few rules.

C4 has become one of the most widely used approaches to architecture diagrams because it is easy to learn, fits naturally with the multi-view thinking of Section 4.2, and produces diagrams that both developers and non-technical readers can follow. In 42010 terms, each C4 diagram type is a viewpoint with its own model kind; C4 just keeps the set small.

The abstractions: people, software systems, containers, components

C4 is built on four abstractions, plus code. A person is a human user of the system: a customer, a courier, a support agent. A software system is the highest level of abstraction, something that delivers value to its users and is typically owned and built by one team or organisation; the food-delivery platform is one, and so are the payment provider and the maps service it depends on.

A container is something that needs to be running for the system to work: in Brown's words, essentially a runtime boundary around some code that is executed or some data that is stored. Examples are a server-side web application, a single-page app running in a browser, a mobile app, a desktop application, a serverless function, a database schema, a file store or a message topic. Each is separately deployable or runnable, and containers communicate with each other across process boundaries, usually over a network.

A component is a grouping of related functionality behind a well-defined interface, living inside a container and running in the same process as the other components there. In a Java service it might be a set of classes behind an interface; in a Node.js service, a module. Components are not separately deployable; the container is the unit of deployment. Finally, code is the classes, functions and tables that implement a component.

The four core diagrams

LevelScopeShowsMain audienceRecommended?
1. System contextOne software systemThe system as a single box, the people who use it and the other software systems it interacts withEveryone, technical and non-technical, inside and outside the teamYes, for every team
2. ContainerOne software systemThe containers (apps, services, data stores, topics) inside it, their responsibilities, technologies and how they communicateArchitects, developers, operations and support staffYes, for every team
3. ComponentOne containerThe components inside it, their responsibilities and technologies, and their relationshipsArchitects and developersOnly where it adds value; generate it if it must be kept long-term
4. CodeOne componentClasses, interfaces, functions or tables, typically as a UML class or entity-relationship diagramDevelopersRarely; generate on demand from the code for the most complex parts

Level 1: the system context diagram

The system context diagram is the starting point. It puts the system you are describing in the middle as a single box and surrounds it with the people who use it and the software systems it depends on or that depend on it. It deliberately hides all internal detail, including technologies, protocols and internal services. It answers the questions every newcomer, product manager and security reviewer asks first: what is this system, who uses it, and what does it connect to?

Because it hides internals, the context diagram is also the right diagram for discussions with non-technical stakeholders and for scoping: where does our responsibility end? In the food-delivery example below it immediately shows that card payments, routing and push delivery are bought in, which is architecturally significant (each is an external dependency with its own availability, cost and contract) and invisible in most code-level views.

Food-delivery platform: system context

C4 system context diagram for the food-delivery platformSystem context diagram for the food-delivery platformCustomer[Person]Orders food for deliveryRestaurant staff[Person]Prepares and hands over ordersCourier[Person]Collects and delivers ordersBrowses menus, placesand tracks ordersAccepts orders andupdates their statusAccepts jobs andreports deliveriesFood-delivery platform[Software System]Takes orders, takes payment, dispatches couriers, keeps everyone informedTakes card payments usingGets routes and ETAs fromSends notificationsusingPayment provider[Software System, external]Authorises and captures cardsMaps service[Software System, external]Routing, distances, ETAsPush services[Software System, external]Apple and Google push deliveryKeyPersonSystem in scopeExternal systemRelationship, read in direction
Level 1: the platform as one box, with its three kinds of users and three external systems; every element has a name, a type and a description, and every arrow is labelled.

Level 2: the container diagram

The container diagram zooms into the system box and shows the containers inside it: the applications and data stores that make up the system, what each is responsible for, which technology each uses, and how they communicate. For most teams this is the most valuable diagram they own. It shows the major structural decisions (how many deployable units, which communicate synchronously and which through messaging, which own data) and is concrete enough for developers and operations staff while still fitting on one page.

Notice two choices in the diagram below. The message topic for order events is drawn as a container in its own right, because it is a store that producers write to and consumers read from; the C4 guidance offers this explicit style or, alternatively, omitting the topic and writing "via order events topic" on the arrows. Drawing it shows the coupling through the topic clearly. And the asynchronous relationships use a dashed line, which the key explains. The container diagram says nothing about how many copies of each service run, in which region, or behind which load balancer; that belongs in a deployment diagram.

Food-delivery platform: containers

C4 container diagram for the food-delivery platformContainer diagram for the food-delivery platformCustomer[Person]Orders food for deliveryRestaurant staff[Person]Accepts and prepares ordersCourier[Person]Collects and delivers ordersOrders food usingManages orders usingTakes jobs usingCustomer app[Container: Kotlin, Swift]iOS and Android appRestaurant app[Container: React]Web app on a tabletCourier app[Container: Kotlin, Swift]iOS and Android appMakes API calls to[JSON/HTTPS]Makes API calls to[JSON/HTTPS]Makes API calls to[JSON/HTTPS]API gateway[Container: managed API gateway]Authenticates users and routes requestsRoutes requests to[JSON/HTTPS]Routes requests to[JSON/HTTPS]Ordering service[Container: Java]Places orders, takespaymentOrder events[Container: Kafka topic]OrderPlaced, OrderAccepted,OrderCancelled ...Dispatch service[Container: Go]Assigns couriers,tracks deliveriesPublishes[Kafka]Consumes[Kafka]Reads from andwrites to [SQL/TCP]Order database[Container: PostgreSQL]Orders and paymentsConsumes[Kafka]Notification service[Container: Node.js]Sends status messagesFood-delivery platform [Software System]Takes card paymentsusing [HTTPS/JSON]Sends push messagesusing [HTTPS]Gets routes andETAs from [HTTPS]Payment provider[Software System]Authorises card paymentsPush services[Software System]Delivers push messagesMaps service[Software System]Routes, distances, ETAsKeyPersonContainerExternal systemSynchronousAsynchronous
Level 2: the apps, services and data stores inside the platform boundary, with technologies on every element and protocols on every arrow.

Level 3: the component diagram

The component diagram zooms into one container and shows the components inside it. It is aimed at architects and developers working on that container, and it is where the internal structure of a service becomes visible: which part handles incoming requests, where the business rules live, which part talks to the database, how events leave the service.

C4's guidance is to draw component diagrams only where they add value, typically for containers that are complex, risky or changed by many people, and to generate them automatically if they are to be kept for a long time, because component structure changes as often as the code does. For the food-delivery platform, the ordering service qualifies: it handles money, talks to an external provider and must publish events reliably. The diagram below shows a typical structure, including an outbox component that writes events to the database in the same transaction as the order and relays them to Kafka afterwards (the outbox pattern is covered in Chapter 6).

Ordering service: components

C4 component diagram for the ordering service of the food-delivery platformComponent diagram for the ordering serviceAPI gateway[Container: managed API gateway]Routes client requestsPayment provider[Software System, external]Authorises card paymentsSends order requests[JSON/HTTPS]Authorises paymentsusing [HTTPS/JSON]Sends resultsto [HTTPS]Order API[Component: REST controller]Validates order requestsPayment client[Component: HTTP client]Calls the provider withidempotency keysPayment webhook[Component: REST controller]Verifies signaturesOrder workflow[Component: Java service]Applies order rulesand state changesPlaces ordersRequests paymentReports resultsOrder repository[Component: JPA repository]Stores and loads ordersEvent outbox[Component: outbox relay]Publishes events reliablySaves ordersRecords eventsOrdering service [Container: Java]Reads from andwrites to [SQL/TCP]Publishes to[Kafka]Writes and polls outbox rows [SQL/TCP]Order database[Container: PostgreSQL]Orders and outbox rowsOrder events[Container: Kafka topic]Order lifecycle eventsKeyComponentCore logicOther container or systemSyncAsync
Level 3: inside one container, with neighbouring containers and systems shown outside the dashed boundary so each relationship has both ends.

Level 4: code, and the supplementary diagrams

The code level zooms into a component and shows its classes, interfaces or tables, usually as a UML class diagram or an entity-relationship diagram. The C4 guidance treats it as optional and generally not worth drawing by hand: most development environments can generate it on demand, and a hand-drawn copy is out of date as soon as someone refactors. Draw it only for the most important or intricate parts, such as a domain model at the heart of the business (Section 4.4 shows such a class diagram).

Three supplementary diagrams fill the gaps the hierarchy leaves. A system landscape diagram is a context diagram without a single system in focus: it shows all the software systems and people in an organisation or domain, which is useful for enterprise and platform architects. A dynamic diagram shows how elements collaborate at runtime for one scenario, as numbered interactions on a container or component diagram (or as a UML sequence diagram); this is C4's equivalent of the scenarios in 4+1. A deployment diagram shows how containers are mapped onto infrastructure in one environment: deployment nodes such as cloud regions, Kubernetes clusters, virtual machines, managed database services and devices, with the number of instances. C4 recommends one deployment diagram per environment that matters, typically production and perhaps staging.

Notation rules that make diagrams readable

C4 does not prescribe shapes or colours, but it does prescribe what every diagram must say. These rules, condensed from the C4 notation guidance, are what make the diagrams above readable without a meeting to explain them.

Checklist: a C4 diagram that explains itself

  • A title stating type and scopeFor example "Container diagram for the food-delivery platform", so readers know the zoom level at once.
  • A key (legend)Explain every shape, colour, border style, line style and arrowhead used, even if the notation seems obvious. Readers from other teams will not share your conventions.
  • Every element has a name, a type and a descriptionThe type in brackets (Person, Software System, Container, Component) removes ambiguity; one short sentence of responsibility says what the element is for.
  • Technology on every container and component"Container: Java", "Container: PostgreSQL". Technology choices are architecture and readers need them.
  • Every relationship is one-directional and labelledUse one arrow per relationship, labelled with what it does in the direction of the arrow ("Publishes order events to"), never just "uses" or a double-headed arrow.
  • Protocols on relationships between containersJSON/HTTPS, SQL/TCP, Kafka. Synchronous versus asynchronous is one of the most important facts on the diagram.
  • Acronyms explainedWrite them out or define them in the key or glossary.
  • One level of abstraction per diagramNo classes on a container diagram, no servers on a component diagram.
  • Colour as a supplement, not the only signalDiagrams are printed in black and white and read by colour-blind people; use line style and labels as well, and keep colour meanings consistent across diagrams.

Worked example

Worked example: improving a typical team diagram

A team in the food-delivery company shares this description of their whiteboard diagram: five boxes labelled "App", "Backend", "Orders", "DB" and "Stripe"; lines between them with no arrowheads; the Orders box is green and the others blue; there is no title or key. Applying the C4 rules step by step:

Title and levelDecide what the diagram is. It mixes a mobile app, a service and a database, so it is a container diagram. Title it "Container diagram for the food-delivery platform".
Name, type, description"App" becomes "Customer app [Container: Kotlin, Swift] iOS and Android app for ordering food". "Backend" turns out to be the API gateway; "DB" becomes "Order database [Container: PostgreSQL]".
External systems"Stripe" is a product name for an external system. Show it as "Payment provider [Software System]" outside the system boundary, with the vendor named in the description if that matters to readers.
RelationshipsReplace each plain line with one labelled arrow: "Calls [JSON/HTTPS]", "Reads from and writes to [SQL/TCP]", "Authorises card payments using [HTTPS]". The team discovers that one line meant two different things (a call in one direction and a webhook in the other), so it becomes two arrows.
Missing elementsLabelling the arrows exposes that order events reach the dispatch service through a Kafka topic that was not drawn. Add the topic as a container, with dashed asynchronous arrows.
Key and colourThe green box turns out to mean "owned by our team". Add that to a key, or replace colour with a dashed boundary labelled with the team name.
ResultThe diagram has gained a title, a key, three elements and twice as many arrows, yet takes less explanation, because every question a reader would ask is answered on the page.

Most of the value came from labelling the arrows: unlabelled lines hide the most important architectural facts (direction, protocol, synchronous or asynchronous).

The improved diagram exposed a dependency (the topic) that the team itself had forgotten, which is a typical side effect of applying the rules.

Tools: drawing versus modelling

C4 diagrams can be produced with any drawing tool, and many teams start with a whiteboard or a general diagramming application. The C4 site distinguishes two families of tools. Diagramming tools draw boxes and lines; they are flexible and familiar, but the diagrams are independent pictures, so renaming an element means editing every diagram that shows it, and nothing checks that the diagrams agree. Modelling tools hold a single model of people, systems, containers, components and relationships, and generate each diagram as a view of that model; renaming happens once, diagrams stay consistent and the model can be queried and validated.

Structurizr, created by Simon Brown, is the reference modelling tool for C4. Its text-based Structurizr DSL describes the model and the views in a file that lives in version control next to the code. Other options include C4-PlantUML (C4 shapes for PlantUML), Mermaid's C4 diagram support and various commercial modelling tools; Section 4.7, Diagrams as code, shows examples. The choice matters less than the habit: keep the source of the diagrams where the team works, and update it in the same pull request as the change it describes.

Questions people ask

Is C4 a replacement for UML?

Not exactly. C4 defines abstractions and diagram types, not a notation, and it says nothing about many things UML can express precisely, such as state machines or detailed message sequences. Many teams use C4 for structure and borrow UML sequence, state and deployment diagrams where precision is needed (Section 4.4).

How do serverless functions fit into C4?

Each function, or each group of functions deployed together, is a container: a separately deployable unit that runs code. Shared data stores and queues they use are containers too.

Our system is a single deployable monolith. Is the container diagram pointless?

No. A monolith typically still has a web or mobile client, the server application, a database and perhaps a file store and a scheduled job, each a container. The component diagram of the monolith then becomes the most interesting view of its internal modules.

Check your understanding

What is a container in the C4 model, and give two examples that do not involve Docker.

A separately runnable or deployable unit that executes code or stores data. Examples: a mobile app on a phone, a single-page app in a browser, a database schema, a serverless function.

Which two C4 diagrams does the C4 guidance recommend for every team?

The system context diagram and the container diagram.

Where should replica counts, regions and load balancers be shown?

On a deployment diagram, one per environment, not on the container diagram.

Why does C4 insist on one-directional, labelled arrows?

Unlabelled or two-way lines hide what the relationship is (call, data flow, event), which way it goes and which protocol it uses, which are among the most important architectural facts on the diagram.

Next · 4.4UML essentialsUML's status today, Fowler's sketch, blueprint and programming-language modes, and the notation essentials of the six diagrams architects still use, each drawn for the food-delivery platform.Continue →

Sources and further reading

Have a question about this section? ArchitectBot, the course’s AI study assistant, answers from the course first.

Ask: “Should each of our microservices be a container or a separate software system in our C4 diagrams?”