C4 Code Diagram (Level 4): When You Need It and When You Don't
The Code diagram is the most misunderstood level of the C4 model. It's the level most teams skip, the level Simon Brown himself describes as optional, and yet it's also the level that generates the most questions: "Do we really need to draw our classes?" "Isn't this just UML?" "Who maintains this when the code changes?"
The short answer: most of the time, you don't need a C4 code diagram. The longer answer is more interesting, because the cases where level 4 does pay off are exactly the cases where teams lose the most time without it -- dense algorithms, regulated domains, and onboarding into code nobody fully understands anymore.
This guide covers what a C4 code diagram actually shows, why hand-drawing one is almost always a mistake, the specific situations where C4 model level 4 is worth having, and how automated generation flips the cost-benefit calculation entirely.
If you're new to the C4 model, start with our complete guide to the C4 model first -- this article assumes you know the four levels.
What Is a C4 Code Diagram?
The Code diagram is level 4 of the C4 model -- the deepest zoom level. Where the Component diagram (level 3) shows the major building blocks inside a container, the Code diagram zooms into a single component and shows its implementation-level details:
- Classes and their relationships (inheritance, composition, dependency)
- Interfaces and the types that implement them
- Functions and methods, including key signatures
- Data structures like entities, value objects, and DTOs
In practice, a C4 level 4 diagram is usually rendered as a UML class diagram or an entity-relationship diagram. The C4 model doesn't prescribe a notation for this level -- it explicitly delegates to existing standards because the problem of drawing classes was solved decades ago.
Two properties define the Code level:
- Scope: one component. A Code diagram never spans a whole container, let alone a system. It opens up exactly one component -- the
OrderRepository, thePaymentService-- and shows what's inside. - Granularity: real code symbols. Every box on a Code diagram corresponds to an actual class, interface, or function in the source. There is no abstraction left. This is the level where the diagram and the code are supposed to be the same thing.
That second property is precisely why level 4 is so often skipped, as we'll see. (For a quick reference, see the code diagram entry in our glossary.)
Simon Brown's Own Recommendation: Don't Draw It
Here's the part that surprises people encountering the C4 model for the first time: its creator recommends against creating Code diagrams by hand. Simon Brown's guidance is that level 4 is optional, and when you do need it, it should be generated on demand from the source code -- by your IDE, by documentation tooling, or by anything else that reads the actual code -- rather than drawn and maintained manually.
The reasoning is hard to argue with:
- Code changes constantly. A hand-drawn class diagram is accurate for roughly as long as it takes someone to merge the next pull request. Every rename, every extracted method, every new field makes it a little more wrong.
- The information already exists. Unlike a Container diagram -- which captures decisions that live in nobody's head and no single file -- a Code diagram duplicates what the source code already states precisely.
- Tooling does it better. Modern IDEs (IntelliJ, Visual Studio, and friends) generate class diagrams from code in seconds. They're always accurate because they're derived, not drawn.
So the default position for any team adopting C4 should be: model levels 1-3, generate level 4 when needed. Context, Container, and Component diagrams capture knowledge that isn't in the code. The Code level is the code.
When a C4 Code Diagram Is Actually Worth It
"Usually skip it" is not "always skip it." There are real situations where a code-level view earns its place in your documentation.
1. Complex Algorithms and Intricate Designs
Some components implement logic that is genuinely hard to follow by reading files top to bottom: a pricing engine with chained strategies, a state machine governing order lifecycles, a parser with a deep visitor hierarchy. When the structure of the code is the insight -- when understanding which class delegates to which is the whole battle -- a Code diagram compresses hours of code-reading into one picture.
The test: if a senior engineer needs a whiteboard to explain the component to another senior engineer, that whiteboard sketch is a Code diagram waiting to be captured.
2. Regulated and Audited Domains
In finance, healthcare, aviation, and other regulated industries, auditors and assessors often require implementation-level documentation: which class handles cardholder data, where encryption is applied, how the audit trail is written. Here a level 4 diagram isn't a nice-to-have -- it's evidence. The same applies to security reviews and threat modeling, where data flow through specific classes matters.
3. Onboarding into Dense, Long-Lived Code
Legacy components with years of accumulated decisions are brutal for new joiners. A Code diagram of the three or four scariest components in your codebase -- the ones where tribal knowledge is concentrated -- can cut onboarding time dramatically. New developers see the shape of the component before diving into 8,000 lines of it.
4. Documenting Public Contracts and Design Patterns
If a component exposes an API surface that other teams build against, or implements a pattern (Strategy, Observer, hexagonal ports-and-adapters) where the structure is the documentation, a code-level view makes the contract explicit.
When You Don't Need It (Which Is Most of the Time)
Be honest about the inverse cases, because they cover the majority of components in any system:
- The code is readable. A well-named component with clear packages doesn't need a diagram. The folder tree is the diagram.
- Level 3 already answers the question. If someone asks "how does the order service talk to payments?", that's a Component diagram question. Drawing classes adds noise, not signal.
- The component is straightforward CRUD. A handler, a service, a repository, a model. Everyone has seen this shape a thousand times. Documenting it at class level documents nothing.
- Nobody asked. Documentation should answer questions people actually have. If no one has ever needed a class-level view of a component, creating one is effort spent on shelf-ware.
The guiding principle from the broader C4 approach applies here with full force: every diagram you create is a diagram you must maintain. At levels 1-3, the maintenance cost buys you knowledge that exists nowhere else. At level 4, it usually buys you a slightly prettier, slightly stale copy of your source code.
How Automated Generation Changes the Equation
Everything above assumes that someone has to draw and maintain the diagram. That assumption is what made Simon Brown's "skip it or generate it" advice the right call -- the cost of manual level 4 almost never justified the benefit.
Automation removes the cost side of that equation. Archyl's AI discovery analyzes your connected repository and extracts code-level elements -- classes, interfaces, and functions -- directly from the source, attaching them to the right components in your C4 model. Instead of a developer drawing PaymentService and its collaborators in a diagramming tool, the model is populated from what actually exists in the codebase, and it stays connected to the repository it came from.
This changes the question from "is level 4 worth maintaining?" to "is level 4 worth having?" -- a much easier bar to clear. When the code-level view is generated and refreshed rather than hand-drawn:
- It never lies, because it's derived from the source rather than from someone's memory of the source.
- It's navigable in context: you drill down from system to container to component to code in one model, instead of hunting for a PNG in a wiki.
- The cases that were "worth it despite the cost" (audits, onboarding, complex components) become trivially worth it, and the marginal cases become free.
You still apply judgment about which components deserve attention at level 4 -- a generated view of a trivial CRUD component is still noise. But the failure mode shifts from "stale diagram misleads the team" to "unused view that costs nothing."
A Worked Example: Inside a Payment Processing Component
Let's make this concrete. Suppose your Component diagram (level 3) shows a PaymentProcessor component inside your backend API container. Zooming into it at level 4 might reveal:
[PaymentService (interface)]
├── ProcessPayment(order, method) -> PaymentResult
└── RefundPayment(paymentID, amount) -> RefundResult
[StripePaymentService] ──implements──> [PaymentService]
[StripePaymentService] ──uses──> [StripeAdapter] : wraps the Stripe SDK
[StripePaymentService] ──uses──> [RetryPolicy] : exponential backoff, 3 attempts
[StripePaymentService] ──uses──> [PaymentRepository] : persists payment records
[StripeAdapter] ──maps──> [PaymentResult] : translates Stripe responses to domain types
[RetryPolicy] ──raises──> [PaymentFailedError] : after exhausting retries
[PaymentRepository] ──persists──> [Payment (entity)]
Notice what this view answers that level 3 cannot:
- Where is the seam for testing?
PaymentServiceis an interface; tests can substitute a fake without touching Stripe. - Where would a second provider plug in? A
PaypalPaymentServiceimplementing the same interface -- the structure makes the extension point obvious. - What happens on failure? The
RetryPolicyclass owns backoff behavior;PaymentFailedErroris the escalation path. An auditor asking "what happens when a charge fails?" gets an answer from the diagram. - What touches the database? Only
PaymentRepository. Cardholder data flow is traceable, which matters enormously in a PCI-scoped component.
This is a component where level 4 pays for itself: it's financially sensitive, failure handling is non-obvious, and multiple classes collaborate in a deliberate pattern. Contrast it with, say, a UserProfileHandler that reads and writes a profile record -- drawing that at class level would tell you nothing the file tree doesn't.
Common Mistakes with C4 Level 4
Hand-Maintaining Class Diagrams
The classic failure. A motivated engineer draws beautiful class diagrams for the whole codebase; six months later they describe a codebase that no longer exists, and now they actively mislead. If a Code diagram isn't generated from source -- or at minimum regenerated on a schedule -- treat it as expired the day it's drawn.
Documenting Getters, Setters, and Boilerplate
A Code diagram that lists every accessor, constructor overload, and utility method has the same problem as a map at 1:1 scale. Include the elements that carry design intent -- interfaces, key collaborations, the methods that define the contract -- and omit ceremony. Generated views should be filtered, not dumped.
Using Level 4 Where Level 3 Suffices
If your "code diagram" shows things like "the controller calls the service which calls the repository," you've drawn a Component diagram with class-shaped boxes. Collapse it back to level 3. Reserve level 4 for components whose internal structure is the interesting part.
Drawing the Whole Container at Class Level
A 200-class diagram spanning an entire service violates the C4 hierarchy and is unreadable anyway. One Code diagram covers one component. If you can't scope it that tightly, the component boundaries in your level 3 diagram probably need rethinking.
Treating Level 4 as Mandatory for "Complete" Documentation
Some teams adopt C4 with a checklist mentality: four levels, so four sets of diagrams. The result is wasted effort and resentment toward the whole practice. C4 is explicit that level 4 is optional. Three well-maintained levels beat four rotting ones every time.
FAQ
Is C4 level 4 just a UML class diagram?
Mostly, yes -- and that's by design. The C4 model doesn't define its own notation for the Code level; it recommends reusing existing ones, and a UML class diagram is the most common choice (ER diagrams work for data-centric components). What C4 adds is scoping and context: the class diagram describes exactly one component, and that component sits inside a navigable hierarchy of container and system diagrams. A standalone UML class diagram floats free; a C4 code diagram has an address.
Should I create a code diagram for every component?
No. Most components are simple enough that the source code is the best documentation. Reserve level 4 for components that are algorithmically complex, security- or compliance-sensitive, or notorious onboarding obstacles. If documentation is generated automatically, the cost of having more coverage drops -- but attention is still finite, so curate what you surface.
How do I keep a code diagram up to date?
By not maintaining it by hand. Generate it: from your IDE on demand, from documentation tooling in CI, or from a platform like Archyl that extracts classes, interfaces, and functions from your repository during AI discovery and keeps the code level attached to your component model. Any process that relies on a human remembering to update a class diagram after a refactor will fail.
What's the difference between a component and a code element in C4?
A component (level 3) is a logical grouping with a single responsibility -- "the part that handles payments" -- and may span several classes and files. A code element (level 4) is an actual symbol in the source: a specific class, interface, or function. Components are abstractions you choose; code elements are facts the compiler enforces.
The Bottom Line
The C4 code diagram is the level you should skip by default and deploy deliberately. Levels 1-3 capture architectural knowledge that exists nowhere else; level 4 mirrors what the code already says, so it only earns a place when the structure itself is the hard part -- complex algorithms, regulated components, dense legacy code -- and ideally when it's generated rather than drawn.
If you do want code-level views without the maintenance tax, connect a repository to Archyl and let AI discovery extract the classes, interfaces, and functions into your C4 model automatically. You get the depth when you need it, and nobody has to redraw a class diagram ever again.
Want to go one level up? Read the C4 Component Diagram guide, brush up with the complete C4 model guide, or explore the C4 model overview. Ready to try it? Start with Archyl free.