Level 3: Component
We've reached the streets. In the Container diagram we saw the cities of our system — the web app, the API, the database. Now we walk into a single city and look at the individual streets and buildings that make it up. The Component diagram zooms into one container and reveals the major pieces inside it and how they collaborate.
What the Component diagram shows
Pick a single container — say, the Backend API — and open it up. Inside, you don't find one undifferentiated blob of code. You find a set of components: logical groupings of related functionality, each hidden behind a well-defined interface and each with a clear, single responsibility.
The Component diagram answers:
- What are the major building blocks inside this container? (Controllers, services, repositories, and so on.)
- What is each one responsible for? (One clear job per component.)
- How do they collaborate to get work done? (Which component calls which.)
A component in C4 is a grouping of related functionality encapsulated behind a well-defined interface — for example, an "Order Controller," a "Payment Service," or a "Security" component. Importantly, a component is not the same as a single class. It's usually a cluster of classes (or modules, or functions) that together fulfill one responsibility. Think "the part of the code that handles payments," not "the PaymentProcessor.java file."
This is the level for the people writing and maintaining the code inside that container. It gives them a map of the internal structure so they know where a new feature belongs and what they'll touch when they change something.
Who is this diagram for?
The audience narrows again. The Component diagram is squarely for a technical audience working inside the container: software developers and software architects. A product owner rarely needs this level; the developer building the next checkout feature needs it constantly. It's the diagram that answers "where does this new bit of logic go, and what will it depend on?"
Components and bounded contexts
If you've encountered Domain-Driven Design (DDD), the Component diagram is where it often shows up visually. A component frequently maps neatly onto a bounded context — a self-contained slice of the domain with its own clear responsibility and its own vocabulary. An "Orders" component, a "Payments" component, an "Inventory" component: each owns its corner of the business domain and exposes a clean interface to the others.
Drawing components this way pays off in two directions. It keeps the diagram meaningful to the business (each box corresponds to a real capability, not an incidental technical artifact), and it nudges the code toward healthy modularity — because if you can't cleanly draw the components, that's often a sign the container's internals are tangled and the responsibilities aren't well separated. The diagram becomes a gentle design review.
A word of caution, though: components are more volatile than containers. The way you slice up the internals of an API can change with a refactor, which is part of why the next level down (Code) is usually left ungenerated by hand — and why some teams draw Component diagrams only for the containers that are complex or important enough to justify the upkeep.
The building blocks
- ⚙️ Component — a logical building block inside the container, labelled with its name, its technology or type (e.g. "Express Router," "JWT Middleware," "Prisma ORM"), and a short description of its responsibility.
- A container boundary — a box drawn around all the components, showing that they live inside the one container we've zoomed into.
- Surrounding elements — the other containers (like the Web Application and Database) and external systems (like the Payment Gateway) usually appear at the edges, so you can see how the components connect to the outside world.
Relationships remain labelled, directional arrows describing how the components use and delegate to one another.
A worked example: inside the Backend API
Let's zoom into the Backend API container from Level 2. Inside, we find four components that work together to handle an order: a controller that receives HTTP requests, a security component that validates the caller, a payment service that talks to the gateway, and a repository that handles database access.
C4Component
title Component Diagram - Backend API Container
Container(web_app, "Web Application", "React", "Delivers the SPA.")
ContainerDb(db, "Database", "PostgreSQL", "Stores application data.")
System_Ext(payment_gateway, "Payment Gateway", "Stripe")
Container_Boundary(api_boundary, "Backend API") {
Component(order_controller, "Order Controller", "Express Router", "Handles HTTP requests.")
Component(security, "Security Component", "JWT Middleware", "Validates tokens.")
Component(payment_service, "Payment Service", "Node Module", "Interfaces with gateways.")
Component(db_repo, "Database Repository", "Prisma ORM", "Handles DB operations.")
}
Rel(web_app, order_controller, "Requests", "HTTPS")
Rel(order_controller, security, "Uses")
Rel(security, payment_service, "Delegates to")
Rel(security, db_repo, "Delegates to")
Rel(payment_service, payment_gateway, "Calls", "HTTPS")
Rel(db_repo, db, "Queries", "SQL")
The story: the Web Application sends an HTTPS request to the Order Controller, which uses the Security Component to validate the caller's token. From there work is delegated to the Payment Service (which calls the external Payment Gateway) and the Database Repository (which queries the PostgreSQL database with SQL). In one screen, a developer now understands exactly how a request flows through the API and where each responsibility lives — which is precisely what they need before touching the code.
Common beginner mistakes
- Treating a component as a single class. A component is a group of related functionality behind an interface, not one file. If your diagram has fifty boxes, you've zoomed into Level 4 by accident.
- Drawing a Component diagram for every container. You don't have to. Draw them for the containers that are genuinely complex or high-risk. A thin CRUD service may not warrant one.
- Letting it drift out of date. Component structure changes with refactors. If you hand-draw these, budget for maintenance — or better, generate them from the code (see Tooling).
- Mixing in code-level detail. Method signatures and class hierarchies belong to Level 4, not here.
Where we're headed
We've now walked the streets of one container and seen the buildings on them. There's exactly one zoom left: stepping inside a single component to see the actual classes and interfaces that implement it. That's the Code diagram — the level Simon Brown says most teams should feel free to skip, and we'll explain why.
Previous: ← Level 2: Container · Next: Level 4: Code →