Mastering C4 Container Diagrams: A Step-by-Step Guide to Modeling Software System Internals
This article explains the C4 Container Diagram — its purpose, key attributes, notation, and a complete walkthrough using an Internet Banking System example to show how to decompose a system into applications, data stores, and their communication protocols.
1. What Is a Container Diagram?
The previous article covered the System Context Diagram, which places the software system in the center surrounded by users and external systems. That diagram answers where the system sits in the overall landscape. But engineers building the system need more: they need to know what applications and data stores make up the system internally, what key technologies are used, and how those pieces communicate. The Container Diagram answers these questions by zooming one level deeper into the system boundary and showing every container — the applications and data stores that must run for the system to work.
2. Key Attributes
2.1 Intent
A Container Diagram answers five questions:
What applications and data stores is the software system decomposed into?
What is the responsibility of each application and data store?
What are the major technology choices for implementing them?
How do these applications and data stores communicate with each other?
As a software engineer, where should I write code to add a new feature?
The first two questions tell you what the system is made of ; the last three tell you how the pieces fit together and where the engineer's work lands . A completed Container Diagram should give clear answers to all five.
Crucially, a Container Diagram must not involve deployment concerns — cloud environments, servers, Kubernetes clusters, Docker containers, load balancers, firewalls, API gateways, failover setups — none of these belong here. They vary across dev, test, and prod, and including them would make the diagram change with every environment, increasing maintenance cost. Deployment information belongs in a separate Deployment Diagram, one per environment.
2.2 Scope
The scope is exactly one software system . The Container Diagram takes the central box from the System Context Diagram and zooms in. One system = one Container Diagram; multiple systems = multiple diagrams.
2.3 Content
A Container Diagram typically contains four element types: people, software systems, containers, and the boundary of the system being zoomed into.
People and other software systems : Copied directly from the System Context Diagram to maintain narrative continuity — the audience sees the same actors and external systems, just at a finer granularity.
Containers : Each container is an application or data store inside the system. Every container must convey three pieces of information:
Name : What the container is called.
Technology : The implementation stack, e.g., "Java and Spring Boot", "Angular Single-Page Application", "MySQL Database".
Description : A one-sentence statement of the container's responsibility or what entities/tables/files/objects it stores.
During upfront design , some technology details may be undecided; write what you know — even coarse-grained notes like "MySQL or PostgreSQL" or "Relational Database" are better than blanks. For documenting an existing system , all technology details are known and should be fully recorded.
Software system boundary : Draw a dashed rectangle around all containers and label it with the system name. This boundary is a key visual cue of C4's hierarchical abstraction — one glance shows which containers belong to the system and which do not.
Relationships : Container-to-container relationships are shown with unidirectional arrows . Each arrow carries two labels:
Description : What the interaction does, e.g., "Reads data", "Makes API request".
Technology : The primary protocol, e.g., "JSON/HTTP", "SOAP/HTTP", "gRPC".
Container relationships are fundamentally cross-process communication — one container runs on another machine or at least in another process, requiring a process-boundary crossing and often a network hop. Labeling the protocol makes it immediately clear that this is a heavyweight remote call. To distinguish synchronous from asynchronous, use solid lines for synchronous and dashed lines for asynchronous.
2.4 Why It's Useful
The System Context Diagram shows the system as a single box; the Container Diagram opens that box and reveals what's inside. It adds value by:
Making explicit the actual applications and data stores that must be built, deployed, and operated.
Surfacing the major technology choices.
Showing container relationships and communication mechanisms.
Providing a tool for reviewing new architectures or architectural changes.
The last point is often overlooked in fast-paced development. Drawing a Container Diagram before writing code forces you to annotate technology choices, letting the team judge whether the design is realizable.
2.5 Who Needs It
Primary audience: architects and engineers building or maintaining the system . But others benefit too:
Operations and support teams — they need to know exactly what they must run and operate. Many "DevOps" organizations still have a gap: developers don't understand production deployment, and operations don't understand how the system is decomposed into applications and data stores or how they communicate. The Container Diagram bridges this gap; paired with a Deployment Diagram, it aligns Dev and Ops.
QA and test engineers — especially for technical testing like performance testing.
Compliance teams and architecture review boards — architecture reviews, threat modeling, and technical risk assessments can start from this diagram.
Non-technical product owners — they can ask engineers to circle the containers affected by a feature, not for technical review but for a sanity check : confirming the engineer has a clear grasp of the change scope.
3. Drawing a Container Diagram Step by Step
Using the Internet Banking System example from the previous System Context Diagram, we now zoom into the central dashed box and draw all its containers.
3.1 Starting Point: People, External Systems, Empty System Boundary
Same as the System Context Diagram: draw the Personal Banking Customer, Core Banking System, Amazon SES, plus the Core Banking System's dashed boundary — currently empty. Title: "Container View: Internet Banking System".
3.2 Add the Single-Page Application
The UI is a Single-Page JavaScript/Angular Application running in the browser. Place this container inside the system boundary.
3.3 Add Static Content
The SPA's code (HTML, CSS, JavaScript) must be served from somewhere — typically a Web Server or CDN . Add a "Static Content Directory" container for these static files.
Why label it "Static Content Directory" instead of "nginx", "Apache", or "CDN"? Because the hosting mechanism can differ completely across environments — a simple HTTP server in dev, a CDN with caching in prod. The specific hosting approach belongs in the Deployment Diagram.
3.4 Add the Backend API
The UI needs data from the Core Banking System, but cannot connect directly — exposing the Core Banking System to the public internet is a security risk. The solution: introduce a Backend , isolated from the Core Banking System via firewalls, routing, and network segmentation. The Backend exposes a JSON/HTTP API for the UI, and internally calls the Core Banking System's XML/HTTPS API to fetch data.
Technology choice: the bank already uses Java and Spring Boot internally, so we reuse that stack.
3.5 Add the Database
Customers need username/password to log in. The Core Banking System already stores customer data, but it's a commercial product — adding username/password fields would be too costly . So we store them ourselves in a Relational Database . The bank already uses MySQL; we follow suit. Add a "Relational Database Schema" container.
3.6 Add the Statement Store
The system must let customers download PDF bank statements . Transaction lists can be fetched from the Core Banking System, but queries beyond one year have poor performance . To avoid burdening customers with this latency, we cache generated PDF statements . The existing relational database is ill-suited for storing PDF files. The bank has an AWS contract and the system runs on AWS — so we use AWS S3 Object Storage to cache the PDFs. Add a "Statement Store" container.
3.7 Two Ways to Depict AWS Services
Notice two AWS services appear on the diagram but are drawn differently:
Amazon SES (Simple Email Service) : The Java/Spring Boot Backend calls its API to send emails. It is fundamentally an external service we consume . As long as its API is stable, we don't care about its internals, so it is drawn as a Software System (external dependency).
S3 : Although the S3 service itself is operated by AWS, the specific S3 bucket we create is a data store — an integral part of our software system. We control what goes in the bucket, how it's organized, and the data format. Even though hosted elsewhere, this bucket remains part of our system , so it is drawn as a Container , not a Software System.
General principle: If you have full control and responsibility over something, draw it as a Container; if it's just an external service you call, draw it as a Software System.
3.8 Notation and Element Types
This Container Diagram extends the System Context Diagram's notation. Conventions:
Person : Human icon, labeled with Name + Short Description .
Software System : Rounded rectangle, labeled with Name + Short Description .
Container : Shape varies by type (see legend), labeled with Name + Short Description + Technology Choice .
Software System Boundary : Dashed rectangle enclosing all containers.
Relationships : All unidirectional dashed arrows , each with a brief intent description; many also annotated with protocol.
Diagram Title : Uniform format "Container View: System Name".
C4 is notation-agnostic; the above is just one example. Any notation works as long as the team understands it.
Every element on every diagram carries a small-type label explicitly stating its type: [Person], [Software system], [Container]. This eliminates the common ambiguity in architecture diagrams where people stare at a box and ask "Is this a system or a container?" — labeling upfront saves countless verbal explanations.
3.9 Legend
The legend shows all notation used in this Container Diagram. When sharing with the team, distribute the legend alongside the diagram so anyone unfamiliar with the notation can quickly cross-reference. 1. The C4 Model for Visualising Software Architecture, Chapter 4 ↩︎
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
