en_US

Mastering the C4 Container Diagram: Zooming In on Technology Choices, Responsibilities, and Communication (with PlantUML Examples)

What is a C4 Container Diagram?

The Container diagram is Level 2 in Simon Brown’s C4 model. It zooms into a single software system (defined at Level 1 – System Context) to show:

The Ultimate Guide to C4 Model Visualization with Visual Paradigm's AI  Tools - ArchiMetric

  • The high-level shape of the architecture inside your system boundary.

  • Major deployable/runnable units called containers.

  • Technology choices for each container.

  • How containers interact with each other and with external actors/systems.

Important clarification: A “container” in C4 is not necessarily a Docker container. It is any separately deployable/run-time unit that executes code or stores data. Examples:

  • Web application / Single-Page Application (SPA)

  • Mobile app

  • Server-side API / microservice

  • Database (schema)

  • File storage (S3 bucket, file system folder)

  • Message broker / queue (when modeled explicitly)

  • Desktop / CLI application

  • Batch process / scheduled job

The diagram remains high-level — no internal class or code details (that’s Level 3 Components or Level 4 Code).

When to Create a Container Diagram

Create (and maintain) a Container diagram when:

  • You have completed (or at least sketched) the System Context diagram and need to answer: “What are the major building blocks inside our system?”

  • Onboarding new developers, architects, or operations staff — they need to quickly understand technology stack and high-level responsibilities.

  • Making significant technology or architectural decisions (monolith → microservices, adding mobile app, choosing database, introducing message queues, cloud migration).

  • Documenting for audits, compliance, security reviews, or incident response (helps show attack surface, data flows).

  • You want “architecture as code” that lives in the repository and evolves with the system.

  • Most teams stop here — Simon Brown himself notes that System Context + Container diagrams are sufficient for the majority of software teams. Only go deeper (Components/Code) when complexity inside a container justifies it.

Skip or defer if:

  • The system is extremely simple (one process + database).

  • You’re doing very early ideation and only need the big-picture context.

Why Use Container Diagrams? (Key Benefits)

  • Clarity for different audiences
    Developers see technologies and integration points.
    Ops/infra teams see deployable units and communication paths.
    Architects see responsibility boundaries and tech debt risks.
    Managers see a technology-neutral-enough yet concrete view.

  • Avoids the “one big diagram” problem
    Prevents dumping everything (users + infra + classes + cloud icons) into a single overloaded picture.

  • Highlights key decisions
    Clearly exposes choices like SPA + API + relational DB vs. server-side rendering + NoSQL, or synchronous vs. event-driven.

  • Communication & collaboration
    Acts as a shared map during design sessions, incident post-mortems, threat modeling, and roadmapping.

  • Living documentation
    When written in PlantUML / Structurizr DSL / similar → versioned in Git, auto-regenerated on CI, always up-to-date.

How to Create a Great Container Diagram (Step-by-Step + Best Practices)

  1. Start from Level 1
    Copy Persons + external Software Systems from the Context diagram — they become actors that interact with your containers.

  2. Draw the System Boundary
    Use System_Boundary in PlantUML to clearly scope “inside our system”.

  3. Identify Containers
    Ask: What are the separately runnable/deployable things that deliver the system’s functionality?
    Common patterns:

    • Web SPA ↔ API backend ↔ Database

    • Mobile app ↔ Backend-for-frontend (BFF) ↔ Shared services

    • Microservices with message broker

    • Legacy monolith + new API layer

  4. Add Technology & Brief Description
    Every container should show: name, technology, short purpose.
    Keep descriptions < 15 words.

  5. Define Interactions (Relationships)
    Show direction + protocol + intent (e.g., “JSON/HTTPS”, “Reads from and writes to”, “Publishes to”, “Consumes from”).
    Use verbs on relationships.

  6. Best Practices

    • Keep it readable — aim for < 10–12 containers. If more → create focused views (e.g., “API subsystem containers”).

    • Be consistent — same layout direction (top-down/left-right), same level of detail.

    • Use icons/sprites — add visual pop (PlantUML supports devicons, font-awesome, etc.).

    • Legend & key — enable automatic legend in PlantUML.

    • Avoid clutter — omit queues/topics if they don’t add value; label protocols on arrows instead.

    • Version & store as code — commit .puml files to repo.

    • Audience tailoring — one version for devs (detailed tech), lighter version for stakeholders.

PlantUML Example – Classic Internet Banking System (Big Bank plc style)

Here is a clean, production-grade example using the official C4-PlantUML library.

Mastering the C4 Container Diagram: Zooming In on Technology Choices, Responsibilities, and Communication (with PlantUML Examples)

@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

' Optional: add nice icons (from tupadr3 sprites)
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/angular.puml
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/java.puml
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/postgresql.puml
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/android.puml

title Container Diagram: Internet Banking System

Person(customer, "Personal Banking Customer", "A customer of Big Bank plc")

System_Boundary(c1, "Internet Banking System") {
    Container(spa, "Single-Page App", "JavaScript & Angular", "Provides all the internet banking functionality to customers via their web browser", $sprite="angular")
    Container(mobile, "Mobile App", "Android/iOS (React Native)", "Limited internet banking functionality", $sprite="android")
    Container(api, "API Application", "Java & Spring Boot", "Provides Internet Banking functionality via API", $sprite="java")
    ContainerDb_Ext(db, "Banking Database", "PostgreSQL", "Stores user preferences, cached data, sessions (core accounts/transactions remain in mainframe)", $sprite="postgresql")
}

System_Ext(core, "Core Banking System", "Mainframe system – existing")
System_Ext(email, "Email System", "Sends emails (e.g. AWS SES)")

Rel(customer, spa, "Uses", "HTTPS")
Rel(customer, mobile, "Uses", "HTTPS")

Rel(spa, api, "Calls", "JSON/HTTPS")
Rel(mobile, api, "Calls", "JSON/HTTPS")

Rel(api, db, "Reads from and writes to", "JDBC/SQL")
Rel(api, core, "Uses", "JSON/HTTPS")
Rel(api, email, "Sends email using", "HTTPS")

LAYOUT_WITH_LEGEND()
LAYOUT_TOP_DOWN()

@enduml

This renders a clean diagram with:

  • System boundary

  • Technology labels

  • Sprites/icons

  • Clear relationships

  • Legend

You can paste it directly into the PlantUML online server or any compatible IDE/editor.

Use this structure as a template — replace elements with your own system’s names, technologies, and flows. For more advanced styling (themes, custom colors), check the C4-PlantUML GitHub samples.

Happy diagramming — and remember: the goal is effective communication, not UML perfection!

C4 Container Diagram Resource