Mermaid C4 Diagram Syntax & Examples
Reference for Mermaid C4 diagram syntax — C4Context / C4Container / C4Component, Person, System, Boundary, and Rel declarations. Copy-paste architecture examples.
Syntax reference, layout guidance, and ready-to-open examples for this diagram type.
A syntax reference for Mermaid's C4 diagram grammar — read this when you need the exact way to declare a person, system, container, or relationship at the four C4 levels (context / container / component / code), then preview and beautify the result in the editor.
View Mermaid sourcePlain-text diagram syntax — copy or edit directly.
1C4Container2 title Container diagram — ride-hailing platform3 Person(rider, "Rider", "Requests and pays for trips")4 Person(driver, "Driver", "Accepts and fulfils trip requests")5 System_Boundary(platform, "Ride-hailing platform") {6 Container(riderApp, "Rider App", "React Native", "Trip booking, live tracking, payments")7 Container(gateway, "API Gateway", "Kong", "Routing, auth, rate limiting")8 Container(trips, "Trip Service", "Go", "Matching, pricing, trip lifecycle")9 Container(dispatch, "Dispatch Service", "Elixir", "Driver location ingest and assignment")10 ContainerDb(tripsDb, "Trip Store", "PostgreSQL", "Trips, fares, receipts")11 ContainerQueue(events, "Trip Events", "Kafka", "Trip state changes fanned out to consumers")12 Container(notify, "Notification Worker", "Node.js", "Push and SMS fan-out")13 }14 System_Ext(maps, "Maps Provider", "Routing and ETAs")15 System_Ext(payments, "Payment Processor", "Card charges and driver payouts")16 Rel(rider, riderApp, "Books trips with")17 Rel(driver, gateway, "Reports location via", "gRPC")18 Rel(riderApp, gateway, "Calls", "HTTPS / JSON")19 Rel(gateway, trips, "Routes requests to", "HTTP")20 Rel(trips, dispatch, "Requests driver match", "gRPC")21 BiRel(dispatch, maps, "Routes and ETAs", "HTTPS")22 Rel(trips, tripsDb, "Reads and writes", "SQL")23 Rel(trips, events, "Publishes trip events", "Kafka")24 Rel(events, notify, "Consumed by")25 Rel(trips, payments, "Charges fares via", "HTTPS")What is the C4 model
C4 is an architecture documentation model developed by Simon Brown that describes a software system at four levels of zoom: Context (the system and its external users / systems), Container (the deployable / runnable pieces — services, databases, queues), Component (the major code modules inside a container), and Code (the class-level detail, rarely diagrammed). Mermaid supports the first three cleanly with the `C4Context`, `C4Container`, and `C4Component` diagram keywords. The fourth level (Code) is typically expressed with class diagrams instead. Each C4 level is its own diagram; mixing levels in one chart breaks the cognitive model.
The four C4 diagram keywords
Each diagram starts with one of the C4 type keywords. `C4Context` is the outermost zoom — the system shown as a single box with external users and external systems around it. `C4Container` zooms in: the system is decomposed into its containers (services, databases, single-page apps). `C4Component` zooms in further: a single container's internal components are shown. `C4Dynamic` is a Mermaid-specific variant for showing dynamic behaviour at any C4 level. Pick the level by audience: Context for non-technical readers, Container for engineering planning, Component for deep dives.
- `C4Context` — system + external actors (for outside audiences)
- `C4Container` — decompose the system into deployable pieces
- `C4Component` — decompose a single container
- `C4Dynamic` — show runtime behaviour at any level
Element declarations — Person, System, Container, Component
Each level uses different element declarations. `Person(id, "Label", "Description")` declares a human actor. `System(id, "Label", "Description")` declares an internal system (your system). `System_Ext(id, "Label", "Description")` declares an external system you depend on (Stripe, an email service, a third-party API). `Container(id, "Label", "Tech", "Description")` declares a deployable piece — note the extra `Tech` parameter (e.g. "Node.js", "PostgreSQL"). `Component(id, "Label", "Tech", "Description")` works the same way inside a container. Suffix `_Ext` variants exist for every type to mark external elements with a distinct visual style.
- `Person(id, "Label", "Description")` — human / actor (Person_Ext for external)
- `System(id, "Label", "Description")` — internal system (System_Ext for external)
- `Container(id, "Label", "Tech", "Description")` — deployable piece (Container_Ext for external)
- `Component(id, "Label", "Tech", "Description")` — module inside a container
Relationships — Rel and labelled connections
Relationships use `Rel(from_id, to_id, "Label")` for the default arrow. `Rel(from, to, "Label", "Tech")` adds a technology / protocol annotation on the connection (e.g. "HTTPS / API", "AMQP", "JDBC"). Directional variants control the visual direction: `Rel_U` (up), `Rel_D` (down), `Rel_L` (left), `Rel_R` (right) — useful when the auto-layout doesn't match the intended reading direction. `BiRel` declares a bidirectional relationship without two separate arrows. Labelling relationships well is the highest-leverage part of a C4 diagram — readers learn the integration model from the labels, not from the box layout.
Boundaries — group containers and components
Boundaries group related elements visually. `System_Boundary(id, "Label")` and `Container_Boundary(id, "Label")` create a labelled enclosure that other elements are declared inside. Use `Enterprise_Boundary(id, "Label")` to wrap multiple systems that belong to the same organisation. Boundaries are particularly useful at the Container level to show service boundaries: which containers are deployed together, which cross an organisational boundary, which belong to the same product area. Like with subgraphs in flowcharts, prefer one or two levels of boundary nesting — deeper nesting becomes hard to read.
Common patterns & gotchas
Two patterns dominate real C4 diagrams. Context diagrams almost always have the shape: one System box in the centre, two-to-four Person boxes around it, and a few System_Ext boxes for third-party dependencies. Container diagrams typically show 3-8 Container boxes inside the system, with external Persons and Systems still on the periphery. The most common gotcha: mixing levels in one chart — putting both System and Container declarations in the same diagram breaks C4's discipline and produces an unclear hybrid. Second gotcha: forgetting the `"Tech"` parameter on Container / Component (the third positional argument) — the diagram still renders but the technology annotations that make C4 diagrams useful are missing.
- Keep one C4 level per diagram — don't mix System with Container in the same chart
- Always supply the `Tech` parameter on Container / Component for the integration annotations
- Use `_Ext` variants for external (third-party) elements — visual distinction matters
Layout — statement order vs automatic
Mermaid's native C4 renderer has no layout algorithm: elements are packed into rows in the order you declare them, and the only controls are `UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")` (how many shapes / boundaries fit per row) and reordering your statements until the diagram reads correctly. That works for small context diagrams but becomes a fight on anything with boundaries or more than a handful of relationships. Beauty Diagram's editor lays C4 out automatically instead: relationship structure determines placement, boundaries size themselves around their contents (including nested boundaries), and elements declared without any `Rel` are grouped beside related elements of the same kind rather than scattered. The same source renders both ways, so you can keep `UpdateLayoutConfig` lines in the file for native renderers — they're ignored here without error. C4-PlantUML documents are accepted directly too, `@startuml` wrapper and `!include` lines included.
- Native Mermaid: layout follows statement order; tune with `UpdateLayoutConfig` and reordering
- Beauty Diagram editor: automatic layout from relationships and boundaries — no manual tuning
- `UpdateElementStyle` / `UpdateRelStyle` lines are accepted and safely ignored — themes own the styling