A while back, I was tasked with developing a new project idea. Like many developers, I started where I was most comfortable — sketching out user stories to get a feel for the scope. It helped, but I quickly realized something was missing: I needed a way to communicate the bigger picture, not just the interactions.
That’s when the company’s head of engineering pointed me toward the C4 model. Until then, I hadn’t heard of it, but the idea immediately clicked. Instead of creating one overloaded “system diagram,” the C4 model breaks architecture into layers of abstraction — Context, Container, Component, and Code. Each layer tells part of the story, tailored to a specific audience.
Naturally, the next question was: how do I actually draw these diagrams without getting lost in a mess of boxes and arrows? After some research, I stumbled upon Structurizr, a tool purpose-built for C4 diagrams. Unlike traditional drawing apps, Structurizr lets you define your architecture as code, making diagrams consistent, maintainable, and always up to date.
In this post, I’ll walk you through:
-
What the C4 model is and why it matters.
-
How Structurizr brings the C4 model to life.
-
A simple, step-by-step example of creating your first diagrams.
By the end, you’ll see how C4 diagrams and Structurizr can help you move beyond static sketches to living architecture documentation that actually works in practice.
Why software architecture diagrams matter
Every software project, no matter how small it starts, eventually grows into something complex. Features pile up, teams expand, and suddenly the system is no longer something you can keep entirely in your head. At this point, having a way to visualize architecture becomes critical.
But here’s the catch: most diagrams we come across in projects suffer from one (or more) of these problems. Some are too vague, where a single box labeled “Backend” connected to “Frontend” tells you almost nothing. Others swing in the opposite direction and are too detailed, such as UML class diagrams with hundreds of classes and relationships that become unreadable outside the team that created them.
Even when diagrams are useful at first, they often become outdated, having been drawn once for a presentation and then forgotten while the code keeps evolving. Finally, in larger organizations, it’s common to see inconsistencies, where different teams use different diagramming styles, making it difficult to piece together the bigger picture.
The result is predictable: diagrams that nobody trusts and eventually stop being used.
This is why having a structured approach to diagrams matters. Effective diagrams facilitate clear communication with diverse audiences, ranging from developers to product managers to executives. They help onboard new team members faster by showing them how everything fits together. They make it easier to spot gaps and risks in the design before they turn into bigger issues. And they maintain a shared understanding across distributed teams, which is especially valuable in today’s world of remote-first development.
This is exactly the problem the C4 model architecture is designed to solve. By standardizing levels of detail, it ensures you always have the right diagram for the right audience - I cannot emphasise the importance of this enough.
The C4 model in a nutshell
When I first heard about the C4 model, I assumed it was just another type of UML or a new notation to learn. But it’s actually something much simpler — and much more practical. The name comes from the four levels of diagrams it introduces: Context, Container, Component, and Code.
The idea is that no single diagram can capture everything an audience needs to know. Executives don’t need to see class hierarchies, while developers don’t benefit much from a vague box labeled “System.” The C4 model solves this by breaking architecture into layers of abstraction. Each layer zooms in a little further, giving the right amount of detail for the right people.
Here’s how it works:
-
At the Context level, you create the “big picture.” This diagram shows how your software system fits into the wider world — who uses it, what other systems it integrates with, and what its purpose is. For example, imagine a simple “Online Banking System.” A context diagram might show a customer, an employee, the banking system itself, and external systems like a payment gateway.
-
At the Container level, you zoom in to see the high-level building blocks of the system. These are the applications, databases, APIs, and other deployable units that make up your software. Continuing the banking example, this might include a web application, a mobile app, an API backend, and a database.
-
At the Component level, you drill further into one of those containers to see the internal parts that make it work. This might be services, controllers, or modules inside the backend API. For example, a “Payments API” might contain components such as a payment service, fraud detection module, and transaction repository.
-
Finally, the Code level is the most detailed. It shows classes, methods, or source code structures. This level is often optional, since IDEs and auto-generated documentation can handle much of this, but it can be useful when you want to explain tricky parts of the system in more detail.
What makes the C4 model so approachable is its simplicity. It doesn’t require learning a heavy new notation or drawing complicated UML diagrams. Instead, it uses basic boxes and arrows, keeping the focus on clarity. The power comes from consistency: everyone knows what a Context diagram should show versus a Container or Component diagram.
By using these four levels together, you create a “map” of your system that’s easy to navigate. You can start by showing an executive how your product interacts with partners, then zoom in to show a developer exactly where the payment service lives in the codebase — all without switching styles or tools.
Structurizr: the tool for C4 model diagrams
Once I understood the C4 model, my next challenge was figuring out how to actually create the diagrams. Like most developers, my first thought was to open a drawing tool such as draw.io, Lucidchart, etc. However, the more I thought about it, the more I realized that those tools would simply put me back into the same trap: creating manual diagrams that look nice for a presentation but quickly drift out of sync with the actual system.
That’s when I discovered Structurizr. Created by Simon Brown (the author of the C4 model itself), Structurizr is a tool built specifically to support the C4 approach. Instead of treating diagrams as static pictures, Structurizr treats them as living models of your architecture.
What makes Structurizr stand out is its “diagrams as code” philosophy. Rather than dragging boxes around by hand, you describe your system using a simple text-based language. Structurizr then generates diagrams automatically from that description. This approach has some big advantages:
-
Your diagrams can live in version control right alongside your source code.
-
Updates are as simple as editing a few lines of text, which means diagrams can evolve as the system evolves.
-
You can generate multiple diagrams from the same model — context, container, and component views — without duplicating work.
-
Layout and styling can be handled automatically, letting you focus on what to show rather than how to align shapes.
Structurizr is also flexible in how you use it. You can run Structurizr Lite locally for personal projects, use the Structurizr Cloud service for collaboration, or even integrate it into your CI/CD pipeline to keep diagrams refreshed automatically. For teams that prefer open-source, there are exporters to PlantUML, Mermaid, and other diagramming formats, so you’re not locked into a single ecosystem.
In short, Structurizr is not just another drawing tool. It’s a way to make your architecture diagrams reliable, consistent, and easy to maintain, turning them into real documentation rather than throwaway visuals.
Getting started with Structurizr (step-by-step tutorial)
Structurizr works best when it’s quick to try and easy to share. That’s exactly what Structurizr Lite gives you: a self‑hosted, single‑user edition that runs locally (or on a server) and serves a live UI for your C4 model. You keep your models as plain text on disk, Structurizr Lite watches the files, and the browser view updates as you edit. It’s perfect for personal projects, prototyping, and “docs-as-code” workflows where you commit your DSL alongside source code.
Run Structurizr Lite with Docker
There’s an official Docker image, so you don’t have to install anything on your machine besides Docker. The container serves the UI on port 8080 and looks for your workspace files inside the container at /usr/local/structurizr. You simply mount a local folder into that path and start up a container for the first time.
Here’s a minimal Docker Compose setup you can copy:
How to use it:
-
Create a directory for your models. In the Docker Compose example, this is already set up as ./my-workspace.
-
Start the container with docker compose up -d
-
After the first run, you’ll notice that Structurizr Lite has automatically created a hidden directory, a workspace.dsl, and a workspace.json file inside the my-workspace directory. These files form the foundation of your model.
-
Open http://localhost:5700 in your browser, and you’ll see basic diagrams generated from the default DSL.
-
Edit workspace.dsl in your editor of choice and refresh the browser. Structurizr Lite will instantly re-render the diagrams with your changes.
Types of software architecture diagrams with Structurizr (C4 in action)
The simple banking example is great to learn the basics, but let’s look at something more modern: a chat application powered by an LLM with Retrieval-Augmented Generation (RAG).
In this scenario, we’ll model:
-
A User interacting with a Chat Application.
-
The chat application consists of two main containers: a Web Frontend and a Backend API.
-
The backend communicates with an LLM Service and a Vector Database (for document retrieval).
The big picture: system context
This is the essence of a C4 Context diagram: it shows the system in its environment without overwhelming technical detail. Later, you can expand the model with containers (frontend, backend, database, LLM service) and even components, but this high-level view is always the starting point.
Below is the same simple example of the system context without the building blocks of the AI Chat Application — drop it into ./structurizr-workspace/workspace.dsl:
-
Workspace
The root element, workspace, defines the scope of your diagrams. Think of it as a “project” containing both the model (the facts about your system) and the views (the diagrams you generate). -
Model
Inside the model, we define two key elements:
-
A person named User. This represents the human interacting with the system.
-
A softwareSystem named "AI Chat Application". This is our system under consideration. Its description clarifies its purpose: “Provides conversational AI responses using LLM + RAG.”
Within the chatApp definition, we also define the relationship: user -> chatApp "Sends chat requests". This means the user initiates interactions with the chat application, and that relationship will be shown as an arrow in the diagram.
-
Views
The views section tells Structurizr what (and optionally, how) to visualize. In this case, we define a system context view for chatApp. This view will automatically include everything related to the system (include *), and autoLayout lets Structurizr arrange the boxes and arrows neatly - in this case, with the following direction left ->right. We also apply a theme default, which ensures diagrams look clean and consistent without extra styling.

Zooming in: container view
A container in this context doesn’t mean “Docker container” — it refers to any application or data store that can be independently deployed or executed. Think of it as the software pieces that together form your system: web apps, mobile apps, APIs, databases, services, and external integrations.
For our AI Chat Application, the system context view showed only the user and the system as a whole. The container view now opens that box and reveals the internals:
-
A Web Frontend where the user interacts with the chat.
-
A Backend API that manages sessions, authentication, and forwards chat messages for answering.
-
A RAG Service that decides whether to answer the query directly (zero-shot) or perform retrieval-augmented generation before calling the LLM.
-
An LLM Service (like Ollama or OpenAI) that generates natural language responses from prompts.
Here’s how that looks in Structurizr DSL:
What this shows:
-
A User interacts with the Web Frontend, which serves as the entry point to the application.
-
The Backend API manages sessions and authentication while forwarding chat messages for processing.
-
The RAG Service takes responsibility for preparing responses, either by sending the query directly to the LLM (zero-shot) or by enriching it with additional context through retrieval-augmented generation.
-
The LLM Service generates the final response based on the prompt it receives.
-
Each container includes both its technology stack and role description, making the diagram easy to understand for developers, architects, and non-technical stakeholders alike.

The result is a diagram that provides a clear, high-level view of how the system is structured. Developers can see the main building blocks and responsibilities, while product stakeholders can understand the flow of interaction without getting lost in implementation details.
Inside the boxes: component view
So far, we’ve seen the big picture and the main containers that make up the system. But what happens inside one of those boxes? Let’s zoom into the RAG Service, since it’s the heart of the application.
At a glance, the RAG Service has three main moving parts:
-
RAG Engine – the brain of the service. It takes incoming chat messages from the API, decides if the query should go straight to the LLM (zero-shot) or if it needs retrieval, and then builds the final prompt.
-
Retrieval – kicks in when the query needs extra context. It embeds the user’s question and looks up the most relevant chunks.
-
Embedded Vector Store – a lightweight, in-process index (like FAISS, Lucene, or SQLite) where those chunks are stored and retrieved from.
Here’s what that looks like in Structurizr DSL.
What this shows:
-
The Backend API forwards chat messages directly to the RAG Engine, which acts as the brain of the service.
-
The RAG Engine decides whether to answer the query directly (zero-shot) or to enrich it with extra context using retrieval.
-
When retrieval is needed, the engine passes the query to the Retrieval component, which embeds the message and searches for relevant chunks in the Embedded Vector Store.
-
Once the final prompt is prepared, the RAG Engine sends it to the LLM Service (such as Ollama or OpenAI) to generate a natural language response.
-
By breaking the RAG Service into components, the diagram highlights the clear responsibilities inside the service: orchestration, retrieval, storage, and prompt generation.

The result is a diagram that makes the inner workings of the RAG Service easy to follow. Developers can see where embeddings and searches take place, while stakeholders understand that this service is the “smart layer” deciding how to prepare questions for the LLM.
Peeking under the hood: code view
The C4 model has one more level called the Code view, which zooms right down into classes, functions, or database schemas. In reality, very few teams go this far—mostly because IDEs and database tools can generate these diagrams automatically, and keeping them up to date by hand is a lot of work. Structurizr leans into this by not trying to model code-level diagrams directly.
That doesn’t mean you can’t show detail when it matters. If you want to highlight a tricky algorithm, a domain model, or a database schema, Structurizr gives you a simple workaround: image views. You just export a diagram from your IDE (as PNG or SVG) and drop it into your Structurizr workspace as a zoom-in.
For most projects, your Context, Container, and Component views will do the heavy lifting, while Code views serve as optional “close-ups” when you need them. Think of them like snapshots—useful for specific explanations, but not something you need to maintain all the time.
Making the most of the C4 model
Using the C4 model with Structurizr is powerful, but like any tool, it works best when you apply it thoughtfully. The first rule of thumb is to keep diagrams simple and audience-focused. A context diagram for executives should not drown in technical detail, and a component view for developers shouldn’t gloss over important responsibilities. Always ask yourself: who will look at this diagram, and what do they need to understand?
Another important practice is to avoid modeling everything. It’s tempting to capture every microservice, class, or database table, but that leads to clutter and quickly outdated diagrams. Instead, focus on the parts of the system that are worth talking about—those that affect communication, design decisions, or onboarding. Clear naming also goes a long way: at higher levels, prefer everyday language over technical jargon so non-technical stakeholders can follow along.
From a workflow perspective, treat your architecture diagrams like code. Keep them versioned alongside your source code so they evolve naturally with the system. Structurizr DSL makes this easy, and when paired with Git, your diagrams stay in sync with development. It also helps to revisit diagrams regularly—for example, during sprint reviews or architecture discussions—so they remain living documentation rather than artifacts that collect dust.
So where does this pay off in practice? One common scenario is onboarding: new developers can understand how a system fits together in hours instead of weeks when a good set of diagrams is available. Another is compliance and audits, where regulators or clients want clear documentation of how data flows through your system. Even outside technical circles, diagrams shine when you need to communicate with business stakeholders, helping them see the value and complexity of what’s being built without digging into the code.
Conclusion
The C4 model fixes the problem of messy, inconsistent diagrams by giving us clear levels of abstraction—Context, Container, Component, and (sometimes) Code. Instead of one giant diagram trying to do it all, you get the right view for the right audience.
With Structurizr, putting C4 into practice is simple. Because your diagrams live as code, they stay easy to update, easy to share, and much harder to let rot.
Try Structurizr Lite today — spin it up with Docker and create your first Context and Container diagram for your own system. You’ll be surprised how quickly the big picture comes into focus.
And remember: diagrams should serve people, not the other way around. Keep them light, useful, and part of the conversation.