Deployment Diagrams: The C4 Way to Stop Confusing Everyone

A senior architect at a healthcare tech company was presenting their new microservices platform to the executive team. Fifteen minutes in, the CTO interrupted: "Wait, so where does this actually run? Are we talking containers? VMs? Which cloud regions?" The architect pulled up what they thought was their deployment diagram: A tangled mess of boxes, lines, and AWS icons that looked like it had been designed by a caffeinated spider. The CTO squinted at the screen, then at the architect, then back at the screen. "I’ll just... ask the DevOps team later."
Sound familiar? We’ve all been there. You know your system inside and out, but when it comes time to explain where everything actually lives and how it’s deployed, your diagrams turn into abstract art that would make Picasso proud and your stakeholders confused.
The Deployment Diagram Dilemma
Deployment diagrams are supposed to answer the simplest questions. Where does this service run? What infrastructure do we need? How do the pieces connect in the real world? But, they often end up being the most confusing artifacts in our documentation arsenal.
The problem isn’t that we don’t understand our deployments. It’s that we try to show everything at once: infrastructure, networking, containers, orchestration, monitoring, security. All crammed into one diagram that requires a PhD to decipher. As Simon Brown, creator of the C4 model, puts it: "If you can’t explain your architecture in five minutes, you probably don’t understand it well enough yourself."
This matters because deployment diagrams are where the rubber meets the road. They’re what your DevOps team uses to provision infrastructure, what your security team uses to assess attack surfaces, and what your finance team uses to estimate cloud costs. Get them wrong, you’re not just confusing people, you’re setting everyone up for expensive mistakes.
Think of It as a Travel Itinerary
Before we dive into the C4 approach, let’s establish what a deployment diagram actually needs to accomplish. Think of it like planning a vacation itinerary for a friend. You don’t hand them an entire world atlas with every road, building, and landmark marked. Instead, you show them: "You’ll fly into Denver, stay at the Marriott downtown, take this specific shuttle to the ski resort, and your equipment will be stored in locker 42."
That’s what a good deployment diagram does. It shows the journey your software takes from code to running system: which deployment nodes (servers, containers, regions) host which containers (applications, services, databases), and how they’re connected in the physical world. Not every cable, not every firewall rule, not every load balancer setting. Just the essential topology that helps people understand where things live and how they communicate.
What Actually Goes in the Box
Let’s break down what makes a C4 deployment diagram different from the infrastructure spaghetti you might be used to.
Deployment Nodes: The Physical Homes
A deployment node represents something that can execute or host software. This could be:
- Physical Infrastructure: Bare metal servers, network appliances
- Virtualized Infrastructure: VMs, virtual networks
- Containerized Infrastructure: Kubernetes clusters, Docker hosts
- Cloud Services: AWS regions, Azure resource groups, managed services
- Client Devices: Web browsers, mobile devices, desktop applications
The key is that deployment nodes can be nested. You might have an AWS Region containing a VPC, which contains an EKS cluster, which contains pods. This nesting shows the hierarchical relationship without cluttering the diagram.
deploymentEnvironment "Production" {
deploymentNode "AWS US-East-1" {
tags "Amazon Web Services - Region"
deploymentNode "Production VPC" {
tags "Amazon Web Services - VPC"
deploymentNode "EKS Cluster" {
tags "Amazon Web Services - EKS"
deploymentNode "API Pod" {
containerInstance apiContainer
instances 3
}
deploymentNode "Worker Pod" {
containerInstance workerContainer
instances 5
}
}
}
}
}
Container Instances: What’s Actually Running
Here’s where C4 really proves its value. Instead of drawing your services from scratch on every diagram, you reference the containers you already defined in your Container diagram. A container instance shows where a specific container (from your earlier C4 diagrams) is deployed.
This creates a beautiful thread through your documentation. Your Container diagram shows what your system is made of. Your Deployment diagram shows where those things live.
| Element Type | Purpose | Example |
|---|---|---|
| Deployment Node | Physical or virtual infrastructure | AWS Region, Kubernetes Cluster, Web Browser |
| Container Instance | A deployed instance of a container | 3 instances of "API Application" running in pods |
| Infrastructure Node | Supporting infrastructure | Load balancers, message queues, databases |
| Relationship | How deployed elements communicate | HTTPS over internet, internal VPC traffic |
Relationships: The Real-World Connections
The relationships in a deployment diagram show the actual protocols and infrastructure paths. Not "calls" or "uses", but "HTTPS over port 443" or "PostgreSQL wire protocol over internal VPC network."
This is where you can add deployment-specific details that matter:
apiPod -> databaseNode "Reads from and writes to" "PostgreSQL wire protocol (port 5432)" {
tags "Internal Network"
}
loadBalancer -> apiPod "Forwards requests to" "HTTPS (port 443)" {
tags "TLS Terminated"
}
userBrowser -> loadBalancer "Makes API calls to" "HTTPS (port 443)" {
tags "Public Internet"
}
Time to Build Your First C4 Deployment Diagram
Let’s walk through creating a deployment diagram for a realistic scenario: a multi-tier web application deployed on Azure.
Step 1: Start with Your Deployment Environments
Most systems have multiple environments. Don’t try to show them all in one diagram. Create separate deployment diagrams for each. Start with production, as it’s usually the most complex and important.
workspace {
model {
// First, define your containers (from your Container diagram)
softwareSystem = softwareSystem "Patient Portal" {
webApp = container "Web Application" "React SPA" "TypeScript/React"
apiApp = container "API Application" "REST API" "ASP.NET Core"
database = container "Database" "Patient data" "Azure SQL"
}
// Then define deployment for Production
deploymentEnvironment "Production" {
deploymentNode "Azure East US 2" {
tags "Microsoft Azure - Region"
deploymentNode "Production Resource Group" {
// We’ll add more here
}
}
}
}
}
Step 2: Model Your Infrastructure Hierarchy
Think about the nesting. What contains what? In Azure, you might have: Region > Resource Group > App Service Plan > App Service. In AWS: Region > VPC > Subnet > EC2 Instance.
userNode = deploymentNode "User Browser" {
infrastructureNode "Browser"
}
deploymentNode "Azure East US 2" {
deploymentNode "Production Resource Group" {
cdnNode = deploymentNode "CDN" {
tags "Microsoft Azure - CDN"
webAppInstance = containerInstance webApp
}
deploymentNode "App Service Plan (P2V2)" {
tags "Microsoft Azure - App Service Plans"
deploymentNode "API App Service" {
properties {
"SKU" "P2V2"
"Instances" "2-10 (autoscale)"
"Runtime" ".NET 8"
"Always On" "true"
}
tags "Microsoft Azure - App Services"
apiAppInstance = containerInstance apiApp
instances 2
}
}
deploymentNode "SQL Server" {
tags "Microsoft Azure - SQL Server"
deploymentNode "SQL Database (S2)" {
tags "Microsoft Azure - SQL Database"
databaseInstance = containerInstance database
}
}
}
}
Step 3: Add the Relationships with Deployment Details
Now connect the dots with real-world protocols and infrastructure paths:
softwareSystem = softwareSystem "Patient Portal" {
webApp = container "Web Application" "React SPA" "TypeScript/React"
apiApp = container "API Application" "REST API" "ASP.NET Core"
database = container "Database" "Patient data" "Azure SQL"
webApp -> apiApp "Makes API calls to" "HTTPS (443)"
apiApp -> database "Reads/writes" "TDS Protocol (1433)"
}
userNode -> cdnNode "Views" "HTTPS (443)" {
tags "Public Internet"
}
Step 4: Add Deployment-Specific Details
This is where you capture information that only matters at deployment time:
- Number of instances
- Machine sizes/SKUs
- Scaling configuration
- Geographic regions
- Network zones
deploymentNode "API App Service" {
properties {
"SKU" "P2V2"
"Instances" "2-10 (autoscale)"
"Runtime" ".NET 8"
"Always On" "true"
}
tags "Microsoft Azure - App Services"
apiAppInstance = containerInstance apiApp
instances 2
}
Step 5: Validate with Your Teams
Here’s the real test: show your deployment diagram to three people:
- A developer: Can they identify where their code runs?
- A DevOps engineer: Can they provision the infrastructure from this?
- A non-technical stakeholder: Can they understand the basic topology?
If all three can make sense of it in under five minutes, you’ve succeeded.
But What About...?
Once you’ve mastered the basics, you’ll inevitably face more complex deployment scenarios. Here’s how to handle the most common edge cases while keeping your diagrams clean and understandable.
Multiple Regions and Disaster Recovery
Create separate deployment diagrams for each region, or use a high-level diagram showing just the regional distribution:
deploymentEnvironment "Production - Multi-Region" {
deploymentNode "Primary Region (East US 2)" {
primaryDB = deploymentNode "SQL Server (Primary)" {
infrastructureNode "Primary Database"
}
}
deploymentNode "Secondary Region (West US 2)" {
secondaryDB = deploymentNode "SQL Server (Secondary)" {
infrastructureNode "Secondary Database"
}
}
primaryDB -> secondaryDB "Geo-replicates to" "Azure SQL Geo-Replication"
}
Hybrid Cloud or On-Premises
Use deployment nodes to show the boundary between cloud and on-prem:
deploymentNode "On-Premises Data Center" {
legacySystemNode = deploymentNode "Legacy System Server" {
containerInstance webApp
}
}
deploymentNode "AWS US-East-1" {
apiNode = deploymentNode "Application VPC" {
containerInstance apiApp
}
}
apiNode -> legacySystemNode "Integrates with" "HTTPS over VPN (443)"
Serverless and Managed Services
Serverless functions are containers too. Show them as container instances within the serverless platform:
deploymentNode "AWS Lambda" {
tags "Amazon Web Services - Lambda"
deploymentNode "Order Processing Function" {
properties {
"Memory" "1024 MB"
"Timeout" "30 seconds"
"Concurrency" "100"
}
orderFunctionInstance = containerInstance orderProcessor
}
}
The Rubber Duck Method
The best way to validate your deployment diagram is the "explain it to a rubber duck" test. Or better yet, to a new team member. Walk through these questions:
- Can you trace a user request? Start from a user's device and follow the path through every deployment node to the database and back.
- Can you identify single points of failure? Look for deployment nodes with only one instance or no redundancy.
- Can you estimate the cost? If you can’t roughly calculate cloud costs from your diagram, you’re missing important details.
- Can you explain the deployment process? How does code get from your CI/CD pipeline into these deployment nodes?
Your Deployment Diagram Survival Kit
A good C4 deployment diagram should:
- Show where containers run, not just what they are. Link back to your Container diagram and show the physical/virtual infrastructure hosting each container
- Use nested deployment nodes to represent infrastructure hierarchy without cluttering the diagram with every detail
- Specify real protocols and paths in relationships. "HTTPS over public internet" is infinitely more useful than "uses"
- Create separate diagrams for each environment. Don’t try to show dev, staging, and production in one overwhelming diagram
The C4 deployment diagram is about answering the fundamental question: "Where does my software actually run, and how does it get there?" When your CTO interrupts your next presentation with "But where does this run?", you’ll have a clear, unambiguous answer ready.
Take your most complex system and try to create a C4 deployment diagram for it. Can you explain it to someone in five minutes? If not, you might be trying to show too much. What would you remove to make it clearer? And more importantly, would your DevOps team be able to provision the infrastructure from your diagram alone?
Share this article
Enjoyed this article?
Subscribe to get more insights delivered to your inbox monthly
Subscribe to Newsletter