Skip to content
Connect an agent
Other diagram kinds

C4 diagrams

A C4 diagram shows the architecture of a software system at one level of zoom: who uses it, what it is made of, what one part is made of, where it runs, or how one scenario plays out. It follows the C4 model: people, software systems, containers, components and databases, with the boundaries round them and the relationships between them. It is for anyone, human or AI agent, who writes an architecture or design document and wants the picture to say, at a glance, what is inside the system and what is outside it.

TL;DR

QuestionAnswer
What is it for?The C4 views of a system: system context, container, component, deployment, and one scenario in order (dynamic).
How does it start?c4 "Title" view=container, then person, system, container, component, and db for the elements, boundary id "Name" kind=system { for a frame round some of them, and a -> b : "Uses" tech="HTTPS" for a relationship.
How do I show what is inside and what is outside?Write external=on on a person or a system that lies outside the scope of the picture. What is inside is tinted, and an external element is grey with a dashed outline.
What does each box say?Its name, a caption such as [Container: Spring Boot] that says what it is and what it is built with, and its description.
What does each line say?A label, and the protocol or mechanism as a tag at the end of the label. --> draws an asynchronous or optional call and ..> an event.
Can it number the steps?Yes. In view=dynamic the relationships are numbered in the order written.
Can I convert Mermaid?Yes. C4Context, C4Container, C4Component, C4Dynamic and C4Deployment become a C4 diagram. Styling and layout calls are dropped and reported.
How big may it be?80 elements, 160 relationships, 40 boundaries and 4 levels of boundary. Past a limit the diagram is refused with error E140, before anything is drawn. The density warning comes much sooner, at 12 elements.
How is it drawn?A card for each element, a dashed frame with a corner tab for each boundary, and a line with a pill for each relationship. Layout is automatic, and the theme chooses every color.

Ask your agent

Say who uses the system, what it is made of, and how the parts talk to each other, and name the technology of each part and each line. The agent writes the rest.

text
Use Plotwork to draw the container diagram of an online bookshop as a C4 diagram. A customer uses a web shop built with React. The web shop calls an orders service built with Node.js over HTTPS, and the orders service reads and writes a PostgreSQL database. The orders service charges cards through a payment provider that we do not run, so mark it as external. Put the web shop, the orders service and the database in a boundary called Bookshop, and give every box a one sentence description.
text
Use Plotwork to draw the system context of our internal expenses tool as a C4 diagram. Employees submit expenses, managers approve them, and finance exports them to the accounting system, which is external. The tool sends an email to the employee when a claim is decided, through the company email system, which is external too. Write what each person does in the label of their line.
text
Use Plotwork to draw the sign in flow of a mobile banking app as a dynamic C4 diagram. The customer enters a password in the mobile app, the app calls the API over HTTPS, the API checks the hash in the database over JDBC, the database answers, the API returns a session token to the app, and the API asks the email system to warn the customer about a new device. Number the steps.

Example

This is the container view of an internet banking system, the example the C4 model is usually taught with. It shows a person, containers and a database inside a system boundary, two external systems, descriptions and technologies on the boxes, technology tags on the lines, and a dashed line for an asynchronous call.

Internet banking system: container view, 8 elements, 1 boundary, 10 relationships. The containers of the internet banking system and the people and systems around it.

A system context view

The context view is the zoomed out picture: the system as one box, the people who use it, and the other systems it depends on. Keep it to a handful of boxes. A person or a system outside the scope is marked external=on, so the reader sees at once what the team owns.

Internet banking system, context: context view, 5 elements, 6 relationships. Who uses the internet banking system, and which other systems it relies on.

A component view

The component view opens one container and shows what it is made of. The container becomes a boundary with kind=container, and the containers and systems around it stay outside, so the reader sees what talks to what at the edge.

Internet banking system, API application: component view, 10 elements, 1 boundary, 10 relationships. The components inside the API application, and what each one talks to.

A deployment view

The deployment view shows where containers run. A kind=deployment boundary is a deployment node: a solid frame with a server icon, and tech= names what it is, such as an operating system or a runtime. Nodes nest, and the containers sit in the innermost one. Draw only the relationships a reader needs, and draw them between the containers, as in the container view.

Internet banking system, live deployment: deployment view, 4 elements, 6 boundaries, 3 relationships. Where the containers of the internet banking system run in production.

A dynamic view

A dynamic view tells one scenario. Write the relationships in the order they happen, and each line carries its number. The same elements as the container view are enough: the order is the new information.

Sign in to internet banking: dynamic view, 5 elements, 6 relationships. What happens, step by step, when a customer signs in.

The language

A line is one statement. A # starts a comment. Ids are words such as web, api-gateway or _x, text is in double quotes, and options are written key=value. The first line is the header.

The header

Plotwork
c4 "Internet banking system" view=container direction=down desc="What the system is made of."
PartMeaning
c4The kind.
"Title"The title. It is the accessible name of the picture and heads the text description. Optional.
view=context, container, component, deployment, or dynamic. The default is container. Only dynamic changes the picture, by numbering the relationships.
direction=auto (the default), right, down, left, or up. auto draws the diagram left to right when that fits a Markdown column, and otherwise keeps the narrower of left to right and top to bottom.
desc=A plain-language description for the text description. Optional. A desc "text" statement does the same.

Statements

StatementMeaningExample
person, system, container, component or db, then <id> "Name" desc="..." tech="..." external=on icon=<set:name> tone=<tone>An element, drawn as a card. desc= says what it does and tech= what it is built with. external=on marks it as outside the scope of the picture. icon= and tone= replace the ones the type has, and icon=none removes the icon.container api "API application" tech="Spring Boot" desc="Serves the data."
boundary <id> "Name" kind=<kind> tech="..." {, the elements inside, then }A frame with its name and a caption in a corner tab, round the elements written inside it. Boundaries nest to four levels. The } is on a line of its own.boundary bank "Internet banking" kind=system {
<from> -> <to> : "Label" tech="..."A relationship between two elements. The label and tech= are both optional, and either may come alone.spa -> api : "Makes API calls to" tech="JSON/HTTPS"
desc "text"The description of the diagram.desc "How a customer signs in."

tone= takes neutral, blue, violet, aqua, orange, green, amber, or red, and icon= takes a name from the closed list of icons, such as lucide:hard-drive or simple:postgresql. A diagram cannot set a color: the theme chooses every color, in light and dark.

The types of element

Each type has its own caption, tone and icon, so a reader tells them apart before reading a word. The caption is [Type], or [Type: Technology] when tech= is written.

TypeCaptionToneIconUse it for
person[Person]violetlucide:userA user, a role, or an actor.
system[Software System]bluelucide:blocksA whole software system, as one box.
container[Container]bluelucide:boxAn application or a service that runs on its own: a web app, an API, a worker, a mobile app.
component[Component]bluelucide:puzzleA part of a container: a controller, a module, a library.
db[Database]aqualucide:databaseA database, a queue, or any other data store.

An external person or system says so in its caption, as [External System], and is a plain neutral card with a dashed outline whatever its type.

The kinds of boundary

kind=Caption in the tabFrameUse it for
system[Software System]DashedThe system the diagram is about, round its containers. This is the default.
container[Container]DashedOne container, round its components.
enterprise[Enterprise]DashedAn organisation, round the systems and people it owns.
deployment[Deployment Node]Solid, with a server iconA machine, a runtime, or a cluster that containers run on. tech= is its technology.

A frame inside a frame is shaded one step stronger, so nesting reads at a glance.

Relationship arrows

ArrowLineMeaning
->Solid, one headA call or a flow of data.
-->Dashed, one headAn asynchronous or optional call.
..>Dotted, one headAn event: a webhook or a message on a topic.
<->Solid, two headsA two-way call.
<-->Dashed, two headsA two-way asynchronous or optional link.

A relationship always points, so -- is error E100. It joins two elements, and naming a boundary is error E131. It may name an element written later in the diagram. The label is a sentence that starts with a verb ("Reads from", "Sends email using"), and the technology is the protocol or the mechanism ("HTTPS", "JDBC", "AMQP"): the picture sets the technology in a tag at the end of the pill, so write it as a short name and keep it out of the label.

Make it readable

HabitHowExample
Describe every boxOne sentence in desc= says what the element does. A box with only a name makes the reader guess.desc="Stores accounts and audit logs."
Name the technologytech= goes into the caption of a container, a component or a database. Leave it out of a person and of a system, where it means nothing.tech="PostgreSQL"
Mark what is outsideexternal=on on every person and system the team does not own.system mainframe "Mainframe" external=on
Keep one level in a diagramA context view has people and systems, a container view has containers, a component view has components. Split a diagram that mixes them.
Say what a line doesA verb in the label, and the protocol in tech=.a -> b : "Reads from" tech="JDBC"

Limits and warnings

Warnings never stop a diagram from being drawn. Errors do.

LimitValueWhat happens past it
Elements80E140
Relationships160E140
Boundaries40E140
Nesting of boundaries4E140
Layers skipped by relationships1,000E140
Elements before the density warning12, plus 2 for each boundary, up to 20W200
A relationship's label, and its technology400 and 200 pxCut with an ellipsis, W203
The text of a cardThe widest card, 400 pxCut with an ellipsis, W203

Layers skipped counts how far relationships jump over the rest of the diagram: a line that passes over many layers makes the layout work much harder than the number of boxes suggests, so that number is limited too. The limits are checked from the text alone, so a diagram that is too big is refused at once with a hint on how to split it.

CodeSeverityWhenFix
E140errorThe diagram is over a limit in the table above.Split the diagram by level.
E100, E101, E110, E111, E121 to E123, E130, E131, E133 to E136errorThe shared codes: a syntax error, an unterminated string, an unknown statement or header, an unknown tone, icon, or direction, a duplicate id, an unknown element, an unclosed or unmatched block, an unknown option, or a bad option value.The message names the line and says what to write. For an unknown element it gives the nearest id.
W200warningThere are more elements than the density limit.Split the diagram into a context diagram, a container diagram, and a component diagram.
W201warningAn element has no relationship at all, in a diagram that has relationships.Connect each person to the system they use and each other element to what it talks to, or remove it.
W202warningThe diagram is wider than a column would keep readable.Use direction=down, shorten the labels, or split it.
W203warningText was cut with an ellipsis.Shorten the text, or move the detail into desc=.

An id is shared by elements and boundaries, so a boundary and an element with the same id is error E130.

From Mermaid

C4Context, C4Container, C4Component, C4Dynamic and C4Deployment convert into a C4 diagram, and the header word sets the view. Call convert_mermaid on one diagram, or sync_markdown with convertMermaid for a whole file, as the migration guide describes. The conversion writes a C4 diagram, checks it, and returns nothing for one that would not validate.

Mermaid
C4Container  title Shop containers  Person(customer, "Customer", "Buys books.")  Container_Boundary(shop, "Bookshop") {    Container(web, "Web shop", "React", "The storefront.")    ContainerDb(db, "Orders", "PostgreSQL", "Holds the orders.")  }  System_Ext(pay, "Payment provider", "Takes cards.")  Rel(customer, web, "Browses", "HTTPS")  Rel(web, db, "Reads and writes", "SQL")  Rel_R(web, pay, "Charges cards using", "HTTPS")  UpdateRelStyle(web, pay, $lineColor="red")

The converter writes this, and reports one warning M202 for the direction of Rel_R and one M200 for the dropped UpdateRelStyle:

Plotwork
c4 "Shop containers" view=container
person customer "Customer" desc="Buys books."boundary shop "Bookshop" kind=container {  container web "Web shop" tech="React" desc="The storefront."  db db "Orders" tech="PostgreSQL" desc="Holds the orders."}system pay "Payment provider" desc="Takes cards." external=on
customer -> web : "Browses" tech="HTTPS"web -> db : "Reads and writes" tech="SQL"web -> pay : "Charges cards using" tech="HTTPS"

What is kept

MermaidPlotworkNote
Person, System, Container, Componentperson, system, container, componentA person and a system take a description, and a container and a component a technology and then a description. An unquoted label is kept as written.
SystemDb, ContainerDb, ComponentDbdbA database of any level.
Each of those with _Extexternal=on
Enterprise_Boundary, System_Boundary, Container_Boundaryboundary with kind=enterprise, system, container
Deployment_Node, Nodeboundary with kind=deployment and the type as tech=
Rel, BiRel-> and <-> with the label and tech=
Rel_BackThe line with its ends swapped
RelIndex-> in a dynamic viewThe lines are ordered by their index, and the numbers follow.
title, a front matter title:, accTitle, accDescrThe title and desc=A front matter title wins.
%% comment on a line of its ownIgnored

What is dropped or changed

MermaidWhat happensCode
UpdateElementStyle, UpdateRelStyle, UpdateBoundaryStyle, AddElementTag, AddRelTag, AddBoundaryTag, and the $tags and $sprite argumentsDropped. The theme owns every color, and the box type and tone= say what an element means.M200
The $link argumentDropped. A diagram is a static picture with no links inside it.M201
UpdateLayoutConfig, Lay_R and the other Lay_ calls, SHOW_LEGEND, and a direction on Rel_U, Rel_D, Rel_L, Rel_R or Node_LDropped. Plotwork lays the diagram out itself. Set direction= on the header to choose the reading direction.M202
The description of a relationship or of a deployment nodeDropped. A relationship has a label and a technology, and a boundary a name and a technology.M203
A generic Boundary, and a SystemQueue, ContainerQueue or ComponentQueueDrawn as the nearest thing: a system boundary, and the element with a queue icon.M204
HTML tags, Markdown marks, line breaks and entities such as &amp; in textDecoded or removed.M205
An alias that is not a valid Plotwork idRenamed. The label keeps the original name.M206
An alias that repeatsThe second one is dropped.M209
An element with no labelNamed with its alias.M216
A boundary that is never closed, or a } that closes nothingRepaired.M217
A line that cannot be read, or a relationship to an element that is not declaredAn error, or with lenient a warning that skips the line.M110, M218
More than 80 elements, 160 relationships, or 4 levels of boundaryAn error. Nothing is converted.M102

See also

DocWhy
Writing diagramsThe flow, sequence, and schema kinds, and the options every kind shares
Examples to copyFinished diagrams with the prompt that gets an agent to write each one
Migrating from MermaidThe converter, its diagnostic codes, and what carries over
Icon referenceEvery icon name you can put in icon=
State diagramsThe lifecycle of one thing, drawn as states and transitions
Class diagramsClasses, their members, and how they relate
Language referenceEvery word of the language, one page for each topic
Diagram kindsThe kinds, and what each one draws