Architecture diagrams drawn by hand go stale the week after the review. Rename one service and you’re editing five boxes in three files, and one of them always gets missed.
Structurizr fixes that by separating the model from the views. You describe your system once in a text file, the Structurizr DSL, and every diagram is a view of that one model. Simon Brown, who created the C4 model, built it.
This guide walks through one example system, an online bookstore, and builds every C4 view for it. Every DSL example here passes structurizr validate (Structurizr 6.2.3), and every image was rendered from the code shown.
What You’ll Learn
- How the Structurizr DSL separates the model from the views.
- How to write system context, container, component, dynamic, and deployment views.
- How to style diagrams and reuse one model across several views.
- How to run Structurizr locally with Docker and export diagrams to Mermaid, PlantUML, or a static site.
- How to validate a workspace in CI so broken diagrams fail the build.
Structurizr Basics
Primary Use Cases
- Documenting a system at several zoom levels that stay consistent with each other.
- Keeping architecture diagrams in version control, next to the code, where pull requests review them.
- Publishing architecture docs and decision records from the same source.
Less Suitable Use Cases
- One-off sketches for a meeting. A whiteboard is faster.
- Diagrams that aren’t about software structure, such as org charts or marketing visuals.
When to Use Structurizr
Use Structurizr when you need more than one diagram of the same system. The first diagram costs about the same as any other tool. The payoff arrives with the second view and every rename after that.
How a Structurizr Workspace Works
A workspace file, workspace.dsl, has two blocks:
modeldefines the elements (people, software systems, containers, components) and the relationships between them.viewspicks which elements each diagram shows.
people, systems, containers,
components, relationships"] A --> C["views
which elements each diagram shows"] B --> D["System context view"] B --> E["Container view"] B --> F["Component view"] B --> G["Dynamic and deployment views"] C --> D C --> E C --> F C --> G
Structurizr Example 1: A System Context View
Start with the smallest useful workspace: one person, two systems, and the context view.
workspace "Bookstore" "An online bookstore used to demonstrate the Structurizr DSL." {
model {
customer = person "Customer" "Browses and buys books."
payments = softwareSystem "Payment Provider" "Processes card payments."
bookstore = softwareSystem "Bookstore" "Lets customers browse and buy books."
customer -> bookstore "Browses and orders books" "HTTPS"
bookstore -> payments "Charges cards" "HTTPS"
}
views {
systemContext bookstore "Context" {
include *
autolayout tb
}
}
}The pieces:
personandsoftwareSystemtake a name, a description, and optional tags.->creates a relationship with a description and a technology.include *shows the system and everything directly connected to it.autolayout tblays the diagram out top to bottom, so you never drag boxes by hand.
The full example below adds a second person and an email service. Its context view renders like this:

Structurizr Example 2: A Container View
Containers are the deployable pieces inside a system: apps, APIs, and databases. Nest them inside the software system, and turn on hierarchical identifiers so you can refer to them as bookstore.web and bookstore.api.
!identifiers hierarchical
model {
bookstore = softwareSystem "Bookstore" "Lets customers browse and buy books." {
web = container "Web App" "Serves the storefront." "TypeScript and React"
api = container "API" "Handles the catalog and orders." "Go"
db = container "Database" "Stores books, customers, and orders." "PostgreSQL" "Database"
}
customer -> bookstore.web "Browses and orders books" "HTTPS"
bookstore.web -> bookstore.api "Calls" "JSON/HTTPS"
bookstore.api -> bookstore.db "Reads and writes" "SQL"
}
views {
container bookstore "Containers" {
include *
autolayout tb
}
}The context view needs no changes. Structurizr implies customer -> bookstore from customer -> bookstore.web, so the system-level diagram stays correct as you add detail. The "Database" tag on the last container picks up a cylinder shape from the styles section later in this guide.

Structurizr Example 3: A Component View
Components live inside a container. Add them to the API and draw relationships at the component level:
api = container "API" "Handles the catalog and orders." "Go" {
catalog = component "Catalog Handler" "Searches and lists books." "Go package"
orders = component "Order Handler" "Places and tracks orders." "Go package"
repo = component "Repository" "Reads and writes the database." "Go package"
}
bookstore.web -> bookstore.api.catalog "Searches books" "JSON/HTTPS"
bookstore.web -> bookstore.api.orders "Places orders" "JSON/HTTPS"
bookstore.api.catalog -> bookstore.api.repo "Reads books"
bookstore.api.orders -> bookstore.api.repo "Saves orders"
bookstore.api.repo -> bookstore.db "Reads and writes" "SQL" component bookstore.api "Components" {
include *
autolayout tb
}Once relationships exist at the component level, the container view derives its arrows from them. Define each relationship once, at the most detailed level you care about.

Structurizr Example 4: A Dynamic View
Static views show what connects to what. A dynamic view shows one request flowing through the system, with numbered steps:
dynamic bookstore "PlaceOrder" "A customer places an order." {
customer -> bookstore.web "Submits the checkout form"
bookstore.web -> bookstore.api "Sends POST /orders"
bookstore.api -> bookstore.db "Saves the order"
bookstore.api -> payments "Charges the card"
bookstore.api -> email "Sends the confirmation"
autolayout tb
}Each step must follow a relationship that already exists in the model, directly or implied. A typo in a step fails validation instead of drawing an arrow that the model doesn’t support.

Structurizr Example 5: A Deployment View
Deployment views map containers onto infrastructure. Add a deployment environment to the model:
production = deploymentEnvironment "Production" {
deploymentNode "Amazon Web Services" {
deploymentNode "us-east-1" {
deploymentNode "Amazon CloudFront and S3" {
containerInstance bookstore.web
}
deploymentNode "Amazon ECS on Fargate" {
containerInstance bookstore.api
}
deploymentNode "Amazon RDS for PostgreSQL" {
containerInstance bookstore.db
}
}
}
} deployment bookstore production "Production" {
include *
autolayout tb
}Add a deploymentEnvironment block for staging and a second deployment view, and both environments share the same containers. That’s how you show where staging differs from production without drawing either one twice.

Style Structurizr Diagrams
Styles match on tags. Every element gets a default tag for its type (Person, Software System, Container, Component), and you can add your own, such as External and Database in this example:
styles {
element "Person" {
shape person
background #08427b
color #ffffff
}
element "Software System" {
background #1168bd
color #ffffff
}
element "Container" {
background #438dd5
color #ffffff
}
element "Component" {
background #85bbf0
color #000000
}
element "Database" {
shape cylinder
}
element "External" {
background #999999
}
}For a quick start, replace the whole styles block with one line inside views:
theme defaultReuse One Model Across Views
Views pick elements from the model, and they can leave relationships out too. This workspace shows the same two elements twice, once for ordering and once for shipping, by excluding the relationship the other view needs:
workspace "Reuse Models" "One model, two views that show different relationships." {
model {
customer = person "Customer"
website = softwareSystem "Website"
orderPlaced = customer -> website "Places an order"
shipmentSent = website -> customer "Emails shipping updates"
}
views {
systemContext website "Ordering" {
include customer website
exclude shipmentSent
autolayout tb
}
systemContext website "Shipping" {
include customer website
exclude orderPlaced
autolayout tb
}
}
}Naming a relationship (orderPlaced = ...) lets a view include or exclude it by identifier. The model stays single-sourced, and each audience sees only the relationships that matter to it.
Run Structurizr Locally With Docker
Structurizr local is the free, open source viewer and layout editor. It replaced Structurizr Lite, and it runs from the structurizr/structurizr Docker image. Put workspace.dsl in a folder and mount that folder:
mkdir -p ~/structurizr
docker pull structurizr/structurizr
docker run -it --rm -p 8080:8080 \
-v ~/structurizr:/usr/local/structurizr \
structurizr/structurizr localOpen http://localhost:8080. If the folder is empty, Structurizr creates a starter workspace.dsl. Edit the file, save it, and refresh the browser to see the change. Layout changes you make in the diagram editor save automatically.
To try the DSL without installing anything, paste a workspace into the Structurizr playground.
Validate and Export Structurizr Diagrams
The same image runs the command-line tools. Validate a workspace before you commit it:
docker run --rm -v "$PWD:/usr/local/structurizr" structurizr/structurizr \
validate -workspace /usr/local/structurizr/workspace.dslvalidate prints nothing and exits 0 when the workspace is valid. On an error it exits 1 and names the line, which makes it a one-line CI check:
ERROR ... Unexpected tokens (expected: ... ->) at line 8 of /usr/local/structurizr/workspace.dslExport every view to another format with export:
# Mermaid, one .mmd file per view
docker run --rm -v "$PWD:/usr/local/structurizr" structurizr/structurizr \
export -workspace /usr/local/structurizr/workspace.dsl -format mermaid -output /usr/local/structurizr/mermaid
# PlantUML, or plantuml/c4plantuml for C4-PlantUML
docker run --rm -v "$PWD:/usr/local/structurizr" structurizr/structurizr \
export -workspace /usr/local/structurizr/workspace.dsl -format plantuml -output /usr/local/structurizr/plantuml
# A static HTML site you can host anywhere
docker run --rm -v "$PWD:/usr/local/structurizr" structurizr/structurizr \
export -workspace /usr/local/structurizr/workspace.dsl -format static -output /usr/local/structurizr/siteThe Docker image doesn’t export PNG or SVG. For images, open a view in Structurizr local and use its export button.
Learn Structurizr: Beyond the Basics
- Structurizr DSL language reference: every keyword, with examples.
- Structurizr DSL cookbook: short recipes for each view type, groups, perspectives, and more.
- Structurizr local quickstart: the official Docker setup.
- Structurizr commands:
validate,export,inspect, and the rest. - The C4 model: the abstractions and notation behind every Structurizr view.
Related Content
- Learn Software Architecture covers the C4 model and the design decisions these diagrams document.
- Fundamentals of Software Architecture explains the boundaries and communication paths a container view makes visible.
- Learn Mermaid covers diagrams as code for everything that isn’t a C4 view.
- Structurizr vs Mermaid vs PlantUML compares this DSL against the two renderers it exports to, on the same model.

Comments #