The Context Diagram gave you the “who” and “what.” The Container Diagram gives you the “how” and “where.” It’s the sweet spot in the C4 model where technical reality meets architectural clarity.

At this level, you stop talking in business abstractions and start mapping the actual deployable units that make your system run. You’ll bridge the gap between product stakeholders (who need to understand data flow and dependencies) and engineering teams (who need to know tech stacks, boundaries, and integration points). After reading this guide, you’ll be able to draft, review, and maintain a Container Diagram that accelerates onboarding, clarifies architecture decisions, and prevents costly misalignments.
In the C4 model, a Container Diagram is Level 2. It zooms one level deeper than the Context Diagram by breaking your single “System in Scope” into its independently runnable or deployable pieces.
What “Container” actually means in C4:
A container is any application or data store that runs in its own process space. It is not necessarily a Docker container. It’s a logical runtime boundary. Examples: a web application, a mobile app, a backend API, a relational database, a message queue, or a file storage service.
How it differs from the Context Diagram (Level 1):
| Context Diagram (Level 1) | Container Diagram (Level 2) |
|---|---|
| Shows 1 system in scope | Breaks that system into multiple containers |
| Focuses on people & external systems | Focuses on technical building blocks |
| No technology details | Explicitly shows tech choices (e.g., React, PostgreSQL, Kafka) |
| For stakeholders & product teams | For developers, architects, DevOps, and tech leads |
Who should use it and when:
Engineering teams during system design, architecture reviews, incident post-mortems, and developer onboarding. Use it when you’re ready to decide tech stacks, plan deployments, or clarify data flow. Skip it if you’re still in early ideation or if the system is a single monolith with no external dependencies.

Applications: Web apps, mobile apps, SPAs, serverless functions, CLI tools
Data Stores: SQL databases, NoSQL databases, object storage, caches
Messaging/Integration: Message brokers, event streams, API gateways
External Services: (Carried over from Context) Payment gateways, SSO, third-party APIs
Logical: How the system is conceptually split (e.g., “User Service,” “Reporting Engine”)
Deployable: How it actually runs in production (e.g., “user-service.jar,” “reporting-db-aurora”)
Best practice: Align logical and deployable boundaries whenever possible. If they diverge, note it in documentation.
Customer Web App (React/TypeScript)
Order API (Java/Spring Boot)
PostgreSQL Database
Redis Cache
RabbitMQ Message Broker
“Is a Docker container a C4 container?” → Only if it represents a distinct runtime unit. A single Docker container hosting a monolith is still just 1 C4 container.
❌ “Should I show load balancers or Kubernetes pods?” → No. Those are infrastructure/deployment concerns. C4 focuses on software architecture, not topology.
✅ Fix: Stick to independently deployable/runnable software units. Keep infrastructure for deployment diagrams or runbooks.
Visualize tech stack decisions in context
Clarify data flow and integration patterns
Identify single points of failure or tight couplings
Align developers, DevOps, and architects on boundaries
What technologies are we using and where?
How do containers communicate? (Sync vs async, protocols)
Where is data stored and how is it accessed?
What external systems are we tightly coupled to?
Developers get a clear map of dependencies. Architects can spot anti-patterns early. Stakeholders understand where data lives and how features are technically delivered. It becomes the single source of truth for technical onboarding.
✅ Do: When designing a new system, refactoring a monolith, onboarding new engineers, or planning cloud migration.
❌ Don’t: For trivial scripts, during early brainstorming, or when you’re already deep in component-level design (jump to Level 3 instead).
| Element | Representation | Purpose |
|---|---|---|
| System Boundary | Dashed rectangle around containers | Groups all containers belonging to your system |
| Containers | Solid rectangles with tech tags | Independent runtime units (apps, DBs, queues) |
| Users | Person icons (optional) | Retains context from Level 1 |
| External Systems | Different color/style | Third-party services your containers talk to |
| Relationships | Directed arrows with labels + tech | Data flow, sync/async, protocol (e.g., HTTPS, JDBC, AMQP) |
| Technology Tags | Inside or below container boxes | Explicit stack choices (critical at this level) |
Step 1: Start from your Context Diagram
Keep your Level 1 diagram open. You’ll reuse the same users and external systems. Your single “System” box is now a boundary you’ll fill with containers.
Step 2: Break the system into containers
Ask: “What runs independently?” List web apps, APIs, databases, caches, queues. Keep it to 5–9 containers max.
Step 3: Add users and external systems
Place users on the left, external systems on the right. Keep the same names from your Context Diagram for consistency.
Step 4: Define relationships and technology
Draw arrows between containers. Label them with what flows + protocol. Add tech tags to every container (e.g., Node.js, MongoDB, gRPC).
Step 5: Add clear labels and legends
Use a consistent naming pattern: [Purpose] ([Technology]). Add a legend if you use custom colors or line styles.
Beginner Checklist:
All containers have explicit technology tags
No component/class details leaked in
Arrows labeled with data/protocol
External systems clearly distinguished
Readable by a mid-level engineer in 60 seconds

@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
title C4 Container Diagram - Blog Platform
Person(user, "Reader", "Views and comments on blog posts")
System_Ext(cdn, "CDN Provider", "Delivers static assets globally")
Container_Boundary(blog_system, "Blog Platform") {
Container(web_app, "Web Application", "React, TypeScript", "Serves UI, handles routing & state")
Container(api, "Blog API", "Node.js, Express", "CRUD operations, auth, comment moderation")
ContainerDb(db, "PostgreSQL", "Relational Database", "Stores posts, users, comments")
Container(cache, "Redis Cache", "In-memory Store", "Session storage & hot post caching")
}
Rel(user, web_app, "Views pages", "HTTPS")
Rel(web_app, api, "Fetches data", "HTTPS/REST")
Rel(api, db, "Reads/Writes data", "JDBC")
Rel(api, cache, "Caches sessions", "TCP")
Rel(web_app, cdn, "Loads assets", "HTTPS")
@enduml

@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
title C4 Container Diagram - Task Manager Mobile App
Person(user, "Mobile User", "Creates and tracks daily tasks")
Container_Boundary(task_system, "Task Manager System") {
Container(mobile_app, "iOS/Android App", "Swift, Kotlin", "Offline-first UI, local sync")
Container(api_gateway, "API Gateway", "AWS API Gateway", "Route & throttle requests")
Container(task_service, "Task Service", "Python, FastAPI", "Business logic, CRUD")
ContainerDb(dynamo, "DynamoDB", "NoSQL Database", "Stores tasks & user profiles")
ContainerQueue(queue, "SQS Queue", "Message Queue", "Async notification jobs")
Container(notifier, "Notification Worker", "Node.js", "Sends push/email alerts")
}
System_Ext(apns, "Apple Push Service", "iOS notifications")
System_Ext(fcm, "Firebase Cloud Messaging", "Android notifications")
Rel(user, mobile_app, "Creates tasks", "HTTPS")
Rel(mobile_app, api_gateway, "Syncs data", "HTTPS")
Rel(api_gateway, task_service, "Routes requests", "HTTPS")
Rel(task_service, dynamo, "Persists tasks", "AWS SDK")
Rel(task_service, queue, "Enqueues alerts", "AWS SDK")
Rel(queue, notifier, "Triggers worker", "AMQP")
Rel(notifier, apns, "Sends iOS push", "HTTPS")
Rel(notifier, fcm, "Sends Android push", "HTTPS")
@enduml

@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
title C4 Container Diagram - E-Commerce Microservices
Person(customer, "Customer", "Shops and tracks orders")
Container_Boundary(ecommerce, "E-Commerce Platform") {
Container(frontend, "Web Frontend", "Next.js", "Product browsing & checkout UI")
Container(order_svc, "Order Service", "Java, Spring Boot", "Order lifecycle management")
Container(inventory_svc, "Inventory Service", "Go", "Stock tracking & reservations")
ContainerDb(order_db, "Order DB", "PostgreSQL", "Order & payment records")
ContainerDb(inv_db, "Inventory DB", "MongoDB", "Product stock data")
ContainerQueue(events, "Event Stream", "Apache Kafka", "Cross-service async events")
}
System_Ext(payment, "Stripe API", "Payment processing")
Rel(customer, frontend, "Places orders", "HTTPS")
Rel(frontend, order_svc, "Submits checkout", "gRPC")
Rel(order_svc, order_db, "Stores orders", "JDBC")
Rel(order_svc, events, "Publishes OrderCreated", "Kafka")
Rel(events, inventory_svc, "Consumes events", "Kafka")
Rel(inventory_svc, inv_db, "Updates stock", "Mongo Driver")
Rel(order_svc, payment, "Charges card", "HTTPS/REST")
@enduml
Poor: Boxes labeled Service1, DB, Queue with no tech tags, arrows labeled calls, uses, or missing entirely. Component details (classes, packages) mixed in.
Clear: [Purpose] ([Tech]) naming, explicit protocols on arrows, logical grouping, zero implementation leakage, readable data flow direction.
Layout tips: Place users left, externals right. Group related containers vertically or in bounded zones. Use auto-layout tools to reduce crossing lines.
Naming conventions: [Business Function] ([Technology]). Example: User Auth Service (Node.js), Analytics DB (ClickHouse).
How much detail is enough? Stop at independently deployable units. If you’re drawing internal modules, packages, or classes, you’ve crossed into Level 3 (Component Diagram).
Colors & styling: Use Visual Paradigm’s built-in C4 theme. Keep containers in one palette, externals in another, and databases/queues in distinct but harmonious shades. Add a legend only if deviating from defaults.
Native C4 Model diagram type with dedicated stencils
Built-in relationship routing, alignment, and theme presets
Tech tag fields built into container properties
Seamless export, versioning, and team sharing (Desktop & Online)

Drag Container from the palette.

Draw System Boundary around your containers.

Use Relationship connectors; double-click to add labels & protocol
Right-click containers → Open Specification → Fill Technology field

Open AI Diagram Generator (Tools > AI Diagram Generator). Select C4 Model to be the diagram type, Containers to be the diagram.
Prompt: Create a C4 Container Diagram for a task management app. Containers: Mobile App (Swift/Kotlin), API Gateway, Task Service (Python), DynamoDB, SQS, Notification Worker. External: APNS, FCM. Show data flow and protocols.

Review generated layout, adjust tech tags, refine arrow labels
| Aspect | Traditional Manual | AI-Assisted |
|---|---|---|
| Control | High precision, custom styling | Fast baseline, requires tuning |
| Learning | Teaches C4 structure deeply | Accelerates drafting, needs verification |
| Best For | Complex domains, strict governance | Rapid prototyping, team alignment |
| Tech Tags | Manually added via properties | Often auto-inferred, always verify |
Open Visual Paradigm Desktop
Launch Visual Paradigm. Select Project New from the main menu.
Name it System_Containers_v1. Click Create Blank Project to confirm.

In the New Diagram window, select C4 Container Diagram.
Drag a System Boundary shape. Rename it to your system name.

Inside, place 3–5 Container shapes.

Place System_Ext right.
Connect with Relationship arrows. Double-click each arrow → add label + protocol.
Select each container → Open Specification panel → fill Technology field.
Open Tools > AI Diagram Generator
Paste a structured prompt (see examples above)
Click OK. VP places shapes, draws arrows, and applies C4 styling.
sends data) with precise ones (publishes order events via Kafka)Open Specification panel for each shape.| Mistake | Why it’s wrong | How to fix it |
|---|---|---|
| Mixing Component-level details too early | Shows packages, classes, or internal modules | Delete anything that isn’t independently deployable. Move internals to Level 3. |
| Forgetting to show technology | Defeats the purpose of Level 2 | Add tech tags to every container. Use VP’s Technology property field. |
| Overloading with too many containers | Creates visual noise & maintenance burden | Cap at 7±2. Group related services logically or split into sub-diagrams. |
| Unclear or missing relationships | Arrows labeled uses or connects to |
Use verb + noun + protocol. Example: Syncs user profiles (gRPC) |
Move to Component Diagrams (Level 3): Drill into 1–2 critical containers to show internal packages, classes, or modules.
Keep diagrams up-to-date: Tie updates to PR templates or architecture decision records (ADRs). Add Last Updated: YYYY-MM-DD in the footer.
Share & get feedback: Use Visual Paradigm’s Share Diagram link for live collaboration. Embed in Confluence, GitHub READMEs, or onboarding wikis. Schedule quarterly architecture reviews.
The Container Diagram is where architecture becomes actionable. It gives developers a clear map of what runs where, how data moves, and what tech choices were made. By mastering this level, you prevent integration surprises, accelerate onboarding, and create a living blueprint that evolves with your system.
Your action plan: Pick one active service or feature. Open Visual Paradigm. Draft a Container Diagram using the 5-step guide. Share it with one developer and one stakeholder. Iterate based on feedback. Do this within 7 days.
✅ 1 system boundary containing 5–9 containers max
✅ Every container has a technology tag
✅ Arrows labeled: data/action + protocol
✅ Users & external systems carried over from Context
No classes, packages, or internal modules
❌ No infrastructure/load balancers/K8s pods
🔄 Version, date, and owner every export
🎨 Use VP C4 theme; distinguish containers vs externals
Container (C4): An independently runnable/deployable unit (app, DB, queue). Not synonymous with Docker.
System Boundary: Visual grouping of containers belonging to your system.
Technology Tag: Explicit stack identifier (e.g., React, PostgreSQL, Kafka).
Relationship Protocol: Communication method (HTTPS, gRPC, JDBC, AMQP, etc.).
Component Diagram: C4 Level 3. Shows internal structure of a single container.
Diagram Type: C4 Model > Container Diagram
Theme: C4 Default or C4 Light (consistent coloring, auto-styling)
Auto-Layout: Hierarchical > Left-to-Right for clean flow
Properties Panel: Enable Technology, Description, Responsibility fields
Export: PNG/PDF > Include Legend > 300 DPI for documentation
AI Assistant: Use structured prompts; always verify tech tags and relationship labels post-generation
Versioning: File > Properties > Version Notes + footer timestamp for audit trails