Vithanco

The C4 Model Notation

Estimated reading time: 9 minutes.

The C4 model describes a software system at four levels of zoom, so that every audience — executives, architects, developers — sees the same architecture at the level of detail it needs. It is the most widely used way to draw software architecture that isn't UML, and Vithanco supports it as a built-in Notation.

What Vithanco adds is this: the four levels are not four diagrams. They are one graph, drawn at different fold states. Collapse the group around a system and you are looking at the System Context view; open it and you are looking at the Container view. Nothing is duplicated, so nothing can drift out of step.

Why use the C4 Model?

C4 answers the question every new joiner, reviewing architect and nervous stakeholder asks — what is this thing, and how does it hang together? — without demanding that they learn a modelling language first. It works because it fixes just two things: a small vocabulary of elements, and four levels of zoom.

Level Question it answers Audience
1. System Context What is this system, who uses it, and what does it talk to? Everybody, technical or not
2. Container What applications and datastores make up the system? Architects, developers, operations
3. Component What are the major building blocks inside one container? Developers working in that container
4. Code How is one component implemented? Rarely drawn — see below

Use C4 when you need to explain a system's place in its environment, show the deployable pieces it is built from, or zoom into one of those pieces without losing the reader. It is particularly strong for onboarding, because a single map stays legible from the boardroom to the codebase.

When NOT to use C4

C4 shows what you built. It never shows why. That is by design — and it is why C4 diagrams age badly on their own: a year later, nobody can remember which options were considered, or which constraint forced the odd-looking split between two containers.

So reach for a different Notation when the question changes:

  • Why is it built this way? Use an IBIS Diagram to capture the question, the options and the arguments for and against each one. C4 has no vocabulary for a rejected alternative; IBIS is made of them.
  • What do these words mean? Use a Concept Map to pin down the domain vocabulary that the boxes are named after, before the same word ends up meaning three things in three containers.
  • What happens when this fails? Use a Causal Loop Diagram to reason about how load, retries and queues feed back on each other. C4 is a structural picture, not a behavioural one.

For the small stuff, you do not have to leave the diagram at all. The Annotation extension works with C4, so you can hang a note on any element:

vgraph banking: C4, Annotation "Internet Banking System" {
    node api: Container "API Application";
    node note: Annotation "Split from the web app in 2024 — see ADR-14";
    edge api -> note;
}

That is the right home for a passing remark. When the remark grows into an argument, move it to IBIS.

The C4 Notation in Vithanco

The diagram below shows every element type at once, with the name you type in VGL as its label. The visual language does most of the work: blue gets lighter as you zoom in, grey means external, a cylinder means datastore, and a notch on top means person.

The element types of the C4 Notation
Every C4 element type, labelled with the name you type in VGL

Unlike the other Notations on this site, there is no meta model picture here. C4 permits relationships between almost any pair of elements, so a drawing of every permitted pair is a wall of arrows that teaches nothing. The table does the job better.

Node Type Description
Person A human user of the system — a customer, an administrator, a support agent.
SoftwareSystem A whole system, drawn as a single box. The unit of the System Context view.
Container A separately deployable or runnable thing: a web app, an API, a mobile app, a datastore.
Database A Container that stores data, drawn as a cylinder.
Component A major structural building block inside one container.
CodeElement A class, interface or module inside a component.
External… Every type above has an External twin — ExternalPerson, ExternalSoftwareSystem, ExternalContainer, ExternalComponent — rendered grey to mark what you do not own or control.

A note on level 4: C4 itself treats the Code level as optional, and Simon Brown advises against drawing it by hand, since an IDE or a documentation generator produces it more accurately and keeps it current. CodeElement exists for when you want it, but the examples below stop at Component, as most real C4 work does.

Relationships

A relationship is a directed edge, and its label carries the meaning — "Uses", "Reads from and writes to", "Makes API calls to", "Sends e-mail using". There is no taxonomy of edge types to memorise; write the phrase that describes how the two elements actually collaborate.

edge api -> db "Reads from and writes to";

Read the label together with the direction, and each edge becomes a sentence: the API Application reads from and writes to the Database. If a relationship needs a paragraph rather than a phrase, that is a signal it belongs in an IBIS Diagram, not on the arrow.

Two words worth getting straight

C4's vocabulary has one trap in it, and the rest of this page depends on avoiding it.

  • Container is an element — a deployable unit like a web application or a datastore. It is not the box drawn around things. This catches people who arrive from the Docker sense of the word, and it catches people who assume the biggest box on the diagram must be the container.
  • Group is the box around things. In VGL you write group, exactly as in every other Notation. A group can carry a type, and C4 calls its typed groups boundaries — hence SystemBoundary, ContainerBoundary and EnterpriseBoundary. An open one draws as a dashed box with its name in the corner.

So a ContainerBoundary is the group drawn around the components of one container. The container itself is the thing that boundary represents.

One graph, three levels

Here is the whole architecture — Simon Brown's Internet Banking System, the canonical C4 example, adapted from c4model.com. Read it once; the next two diagrams are this same source with a single word changed.

vgraph banking: C4 "Internet Banking System" {
    node customer: Person "Personal Banking Customer";
    node mainframe: ExternalSoftwareSystem "Mainframe Banking System";
    node email: ExternalSoftwareSystem "E-mail System";

    group ibs: SystemBoundary "Internet Banking System" {
        node web: Container "Web Application";
        node spa: Container "Single-Page App";
        node mobile: Container "Mobile App";
        node db: Database "Database";

        folded group api: ContainerBoundary "API Application" {
            node signin: Component "Sign In Controller";
            node accounts: Component "Accounts Summary Controller";
            node security: Component "Security Component";
            node mfFacade: Component "Mainframe Banking System Facade";
        };
    };

    edge customer -> web "Uses";
    edge customer -> spa "Uses";
    edge customer -> mobile "Uses";
    edge web -> spa "Delivers";

    edge spa -> signin "Makes API calls to";
    edge mobile -> accounts "Makes API calls to";
    edge signin -> security "Uses";
    edge accounts -> mfFacade "Uses";
    edge security -> db "Reads from and writes to";
    edge mfFacade -> mainframe "Makes API calls to";
    edge signin -> email "Sends e-mail using";
    edge email -> customer "Sends e-mails to";
}

Note the folded in front of group api. A folded group collapses into a single box, and any edge that crossed its boundary is redirected to that box automatically. Because the group is typed as a ContainerBoundary, the box it collapses into is a «CONTAINER» card — the API Application, exactly as the Container view should show it.

Level 2 — the Container view

That source, rendered as written, is the Container view:

The Internet Banking System drawn as a C4 Container view
Level 2 — the Container view. The API Application is a folded group, so it draws as a single «CONTAINER» card.

Level 1 — zoom out to the System Context view

Fold the outer group as well. One word changes:

    folded group ibs: SystemBoundary "Internet Banking System" {
The Internet Banking System drawn as a C4 System Context view
Level 1 — the System Context view. The whole system has folded into one «SOFTWARE SYSTEM» card, and the relationships that crossed its boundary now point at that card.

Every container has disappeared into a single «SOFTWARE SYSTEM» card, and the relationships that used to run from individual containers to the mainframe and the e-mail system now run from the system as a whole. This is a proper System Context diagram, and not one line of it was drawn twice.

Level 3 — zoom in to the Component view

Now go the other way and open the API Application, by deleting the folded we started with:

        group api: ContainerBoundary "API Application" {
The API Application drawn as a C4 Component view
Level 3 — the Component view. Opening the API Application reveals its components, still inside the system they belong to.

The components sit inside their container boundary, inside the system boundary, with the sibling containers still visible around them — which is what makes a Component view readable in the first place. The relationships did not have to be redrawn; they were always between these components, and folding was simply hiding them.

Three C4 levels, three fold states, one source of truth. Change a container's name once and all three views agree, because there is only one place where the name is written down.

What Vithanco checks for you

The C4 Notation carries three quality checks, which run every time the diagram is rendered:

  • A container outside every system boundary. A Container or Database that sits in no SystemBoundary is almost always a modelling slip — it belongs to some system.
  • An external element inside the enterprise boundary. External people and systems are by definition outside the enterprise you are drawing.
  • An element with no relationships. An element that collaborates with nothing is either unfinished or unnecessary.

You can see this for yourself in the editor below: move the node db: Database "Database"; line out of the group ibs block, render, and db is underlined in the source. Hover it, and the warning reads "Container "Database" is not inside any System boundary — a container should live in a system".

Try C4 yourself

The editor below is seeded with the full Internet Banking source, at the Container view. The most interesting thing you can do is a one-word edit: delete the word folded in front of group api, press Cmd+Enter, and you have zoomed into the Component view. Put it back and you are at the Container view again. Add folded in front of group ibs and you are at System Context.

Tip: Use Ctrl+Enter (or Cmd+Enter on Mac) to quickly render your graph while editing.

Want to learn more about the VGL syntax? Check out the complete VGL Guide for detailed documentation on creating graphs in text format, including syntax reference and examples for all supported Notations.

Background

The C4 model was created by Simon Brown in the 2010s as a lightweight, notation-independent way to describe software architecture, distilling ideas from UML and Philippe Kruchten's "4+1" architectural view model into four simple levels. The name comes from those levels: Context, Containers, Components, Code.

The Internet Banking System used throughout this page is Brown's own teaching example, adapted here to VGL.