Read this post in: de_DEes_ESfr_FRhi_INid_IDjapl_PLpt_PTru_RUvizh_CNzh_TW

Beginner’s Guide to C4 Modeling for Agile Enterprise Architecture

C4 modeling is a lightweight way to describe software architecture at different levels of detail. It is especially useful in Agile Enterprise Architecture because teams can create just enough documentation to support a decision, then evolve the diagrams as the solution changes.

Beginner’s Guide to C4 Modeling for Agile Enterprise Architecture

C4 uses four hierarchical levels:

  1. System context — the system, its users, and external systems.

  2. Containers — the major applications, services, databases, and other deployable units inside the system.

  3. Components — the major building blocks inside a container.

  4. Code — classes, interfaces, and implementation details.

C4 also supports supplementary diagrams such as system landscapes, dynamic diagrams, and deployment diagrams. The method is notation- and tool-independent; C4-PlantUML provides a text-based way to create the diagrams.


1. Why use C4 in Agile Enterprise Architecture?

Traditional architecture documentation often becomes outdated because it is created as a large document before implementation starts. C4 modeling supports a more incremental approach:

  • Create diagrams when an architectural decision is needed.

  • Keep diagrams close to the source code and delivery backlog.

  • Review diagrams during refinement, planning, architecture forums, and retrospectives.

  • Model only the level of detail needed by the audience.

  • Update diagrams as part of normal development work.

A useful Agile principle is:

Model the architecture that helps the team make a decision, communicate a dependency, or understand a change.

For example:

  • A product owner may need a system context diagram.

  • A delivery team may need a container diagram.

  • Developers may need a component diagram.

  • A technical specialist may need a code-level diagram.

  • Operations may need a deployment diagram.

Avoid creating all four levels for every system automatically.


2. The C4 abstraction levels

Level 1: System context

A system context diagram answers:

  • What is the system?

  • Who uses it?

  • Which external systems does it interact with?

  • What is inside and outside the system boundary?

It should be understandable to technical and nontechnical stakeholders.

Example:

VPasCode interface displaying C4 system context diagram for Customer Portal, showing users and external systems interactions.

@startuml CustomerPortal_Context

!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml

title System Context Diagram - Customer Portal

Person(customer, "Customer", "A customer who manages orders and support requests")
Person(supportAgent, "Support Agent", "Handles customer questions and service cases")

System(customerPortal, "Customer Portal", "Allows customers to manage orders, profile information, and support requests")

System_Ext(identityProvider, "Identity Provider", "Authenticates customers and support agents")
System_Ext(orderSystem, "Order Management System", "Stores orders and fulfillment information")
System_Ext(notificationService, "Notification Service", "Sends email and SMS notifications")

Rel(customer, customerPortal, "Uses")
Rel(supportAgent, customerPortal, "Uses")
Rel(customerPortal, identityProvider, "Authenticates users with")
Rel(customerPortal, orderSystem, "Reads and updates orders in")
Rel(customerPortal, notificationService, "Sends notifications through")

@enduml

The C4_Context.puml library provides macros such as PersonSystemSystem_Ext, and Rel. C4-PlantUML includes separate libraries for context, container, and component diagrams.

How to use this diagram in Agile work

Create or update the context diagram when:

  • A new external system is introduced.

  • A team is unsure who owns a capability.

  • A product increment changes system responsibilities.

  • You need to explain the product boundary to stakeholders.

  • A dependency creates delivery or operational risk.

Do not put internal services or databases on this diagram. Those belong in the container view.


Level 2: Container diagram

In C4, a container is a separately running or deployable unit, such as:

  • A web application

  • A mobile application

  • An API

  • A microservice

  • A serverless function

  • A database

  • A message broker

A container is not necessarily a Docker container.

A container diagram answers:

  • What are the major parts of the system?

  • What technology does each part use?

  • How do the parts communicate?

  • Which external systems do they depend on?

Example:

VPasCode interface displaying C4 Level 2 container diagram code and visualization for a customer portal system.

@startuml CustomerPortal_Containers

!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

title Container Diagram - Customer Portal

Person(customer, "Customer", "A customer who manages orders and support requests")
Person(supportAgent, "Support Agent", "Handles customer questions and service cases")

System_Ext(identityProvider, "Identity Provider", "Authenticates users")
System_Ext(orderSystem, "Order Management System", "Stores orders and fulfillment information")
System_Ext(notificationService, "Notification Service", "Sends email and SMS notifications")

System_Boundary(customerPortal, "Customer Portal") {
    Container(webApp, "Web Application", "React", "Provides the customer-facing user interface")
    Container(api, "Portal API", "Java, Spring Boot", "Provides APIs for customer and support workflows")
    Container(orderAdapter, "Order Adapter", "Java, Spring Boot", "Translates portal requests into order-system requests")
    Container(notificationWorker, "Notification Worker", "Java, Kafka Consumer", "Processes notification events")
    ContainerDb(portalDatabase, "Portal Database", "PostgreSQL", "Stores portal-specific data such as preferences and support cases")
    Container(messageBroker, "Message Broker", "Apache Kafka", "Distributes asynchronous events")
}

Rel(customer, webApp, "Uses")
Rel(supportAgent, webApp, "Uses")

Rel(webApp, api, "Calls", "HTTPS/JSON")
Rel(api, identityProvider, "Validates tokens with", "OIDC")
Rel(api, orderAdapter, "Requests order information from")
Rel(api, portalDatabase, "Reads from and writes to", "JDBC")
Rel(api, messageBroker, "Publishes events to")
Rel(orderAdapter, orderSystem, "Calls", "HTTPS")
Rel(messageBroker, notificationWorker, "Delivers notification events to")
Rel(notificationWorker, notificationService, "Sends notifications through")

@enduml

The repository documents macros including ContainerContainerDbSystem_BoundaryBoundary, and Rel.

Agile uses for a container diagram

A container diagram is useful during:

  • Solution shaping

  • Architecture runway planning

  • Nonfunctional requirement analysis

  • Team boundary discussions

  • API and integration design

  • Technology selection

  • Risk identification

  • Dependency mapping

For example, a team planning a “customer notification” feature can use the diagram to identify that the change affects:

  • The Portal API

  • The message broker

  • The notification worker

  • The external notification service

  • Monitoring and operational ownership


Level 3: Component diagram

A component diagram zooms into one container. It shows the major logical building blocks inside that container.

Use it when:

  • The container is large or complex.

  • Several teams work on the same service.

  • A new capability requires internal design.

  • Developers need to discuss responsibilities and dependencies.

  • A refactoring decision needs to be communicated.

Example for the Portal API:

VPasCode interface displaying a C4 Level 3 component diagram showing internal structure of a Portal API container with connected components.

@startuml PortalApi_Components

!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml

title Component Diagram - Portal API

Container(webApp, "Web Application", "React", "Provides the user interface")
Container_Ext(orderAdapter, "Order Adapter", "Java, Spring Boot", "Integrates with the order system")
ContainerDb(portalDatabase, "Portal Database", "PostgreSQL", "Stores portal data")

System_Ext(identityProvider, "Identity Provider", "Authenticates users")
System_Ext(notificationService, "Notification Service", "Sends email and SMS notifications")

Container_Boundary(api, "Portal API") {
    Component(authController, "Authentication Controller", "Spring MVC", "Handles login and token-related requests")
    Component(orderController, "Order Controller", "Spring MVC", "Handles order queries and updates")
    Component(supportController, "Support Controller", "Spring MVC", "Handles support-case operations")
    Component(orderService, "Order Service", "Application service", "Coordinates order use cases")
    Component(supportService, "Support Service", "Application service", "Coordinates support-case use cases")
    Component(customerRepository, "Customer Repository", "Spring Data", "Persists customer data")
    Component(supportRepository, "Support Repository", "Spring Data", "Persists support cases")
    Component(eventPublisher, "Event Publisher", "Kafka Producer", "Publishes business events")
}

Rel(webApp, authController, "Calls", "HTTPS/JSON")
Rel(webApp, orderController, "Calls", "HTTPS/JSON")
Rel(webApp, supportController, "Calls", "HTTPS/JSON")

Rel(authController, identityProvider, "Authenticates with", "OIDC")
Rel(orderController, orderService, "Uses")
Rel(supportController, supportService, "Uses")

Rel(orderService, orderAdapter, "Requests order data from")
Rel(orderService, eventPublisher, "Publishes order events")
Rel(supportService, supportRepository, "Reads from and writes to")
Rel(customerRepository, portalDatabase, "Reads from and writes to")
Rel(supportRepository, portalDatabase, "Reads from and writes to")
Rel(eventPublisher, notificationService, "Triggers notifications through")

@enduml

C4-PlantUML uses C4_Component.puml for this level and provides macros such as ComponentComponentDb, and Container_Boundary.

Do not create component diagrams for every service by default. Create one when the internal structure is important to a current delivery decision.


Level 4: Code diagram

The code level describes implementation details such as:

  • Classes

  • Interfaces

  • Modules

  • Methods

  • Relationships

  • Data structures

For most Agile Enterprise Architecture work, manually maintaining detailed code diagrams is unnecessary. Source code, IDE tools, generated documentation, and tests usually provide better detail.

Use a code diagram when:

  • Explaining a complex framework or library.

  • Onboarding developers to a difficult area.

  • Documenting a critical domain model.

  • Planning a significant refactoring.

  • Communicating a reusable design pattern.

The key rule is to stop zooming when the diagram no longer improves communication.


3. Supporting diagrams

System landscape diagram

A system landscape shows several systems in an enterprise or business domain.

It helps answer:

  • Which systems support a business capability?

  • Where are the main integration points?

  • Which systems are candidates for replacement?

  • Which teams or business units own the systems?

Example:

VPasCode tool displaying a C4 System Landscape diagram showing Customer, Portal, and CRM systems within an enterprise boundary.

@startuml Enterprise_Landscape

!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml

title System Landscape - Customer Operations

Enterprise_Boundary(enterprise, "Example Enterprise") {
    Person(customer, "Customer", "Uses digital channels")
    Person(agent, "Support Agent", "Handles customer requests")

    System(customerPortal, "Customer Portal", "Customer self-service")
    System(crm, "CRM System", "Customer and case management")
    System(orderSystem, "Order Management", "Order processing")
    System(billingSystem, "Billing System", "Invoices and payments")
    System(dataPlatform, "Data Platform", "Reporting and analytics")
}

Rel(customer, customerPortal, "Uses")
Rel(agent, crm, "Uses")
Rel(customerPortal, crm, "Creates and reads customer cases")
Rel(customerPortal, orderSystem, "Reads order information from")
Rel(orderSystem, billingSystem, "Creates billing events in")
Rel(crm, dataPlatform, "Publishes customer and case data to")
Rel(orderSystem, dataPlatform, "Publishes order data to")

@enduml

Enterprise_Boundary and related boundary macros are useful for showing groups of systems in a larger landscape.

Dynamic diagram

A dynamic diagram shows how elements collaborate during a particular scenario or use case.

Example: submitting a support request.

VPasCode interface displaying PlantUML code and a generated dynamic C4 diagram illustrating a customer submitting a support request.

@startuml SubmitSupportRequest_Dynamic

!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Dynamic.puml

title Dynamic Diagram - Submit Support Request

Person(customer, "Customer")
Container(webApp, "Web Application", "React")
Container(api, "Portal API", "Java, Spring Boot")
ContainerDb(database, "Portal Database", "PostgreSQL")
Container(messageBroker, "Message Broker", "Kafka")
Container(notificationWorker, "Notification Worker", "Java")
System_Ext(notificationService, "Notification Service", "Email and SMS")

Rel(customer, webApp, "1. Submits support request")
Rel(webApp, api, "2. Sends request")
Rel(api, database, "3. Stores support case")
Rel(api, messageBroker, "4. Publishes SupportCaseCreated event")
Rel(messageBroker, notificationWorker, "5. Delivers event")
Rel(notificationWorker, notificationService, "6. Sends confirmation")

@enduml

The exact dynamic-diagram macros can vary with the C4-PlantUML version. Check the repository’s current samples when using advanced dynamic or sequence features.

Deployment diagram

A deployment diagram shows where containers run.

Example:

VPasCode tool displaying C4 deployment diagram with PlantUML code showing customer, cloud environment, Kubernetes cluster, and application namespaces.

@startuml CustomerPortal_Deployment

!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Deployment.puml

title Deployment Diagram - Production

Deployment_Node(cloud, "Cloud Environment", "Public Cloud") {
    Deployment_Node(kubernetes, "Kubernetes Cluster", "Managed Kubernetes") {
        Deployment_Node(webNode, "Web Namespace", "Kubernetes Namespace") {
            Container(webApp, "Web Application", "React", "Customer-facing web UI")
        }

        Deployment_Node(apiNode, "Application Namespace", "Kubernetes Namespace") {
            Container(api, "Portal API", "Java, Spring Boot", "Customer portal API")
            Container(worker, "Notification Worker", "Java", "Processes notification events")
        }
    }

    Deployment_Node(dataServices, "Managed Data Services", "Cloud services") {
        ContainerDb(database, "Portal Database", "PostgreSQL", "Portal data")
        Container(messageBroker, "Message Broker", "Kafka", "Application events")
    }
}

System_Ext(customer, "Customer", "End user")
System_Ext(notificationService, "Notification Service", "External provider")

Rel(customer, webApp, "Uses", "HTTPS")
Rel(webApp, api, "Calls", "HTTPS/JSON")
Rel(api, database, "Reads from and writes to")
Rel(api, messageBroker, "Publishes events to")
Rel(messageBroker, worker, "Delivers events to")
Rel(worker, notificationService, "Sends notifications through")

@enduml

Deployment diagrams are valuable for discussions about:

  • Availability

  • Network zones

  • Scaling

  • Disaster recovery

  • Security boundaries

  • Operational ownership

  • Environment differences


4. Installing and using C4-PlantUML

C4-PlantUML is a collection of PlantUML macros, stereotypes, and supporting features for creating C4 diagrams. The project includes examples, layout options, and editor snippets.

You have two main inclusion options.

Option A: Include the current repository version

!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml

For a container diagram:

!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

For a component diagram:

!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml

This approach is convenient but requires network access when rendering. The project documentation shows these remote include patterns.

Option B: Use local or standard-library files

For more repeatable builds, use a local copy or the PlantUML standard library:

Or:

The repository also documents downloading the files and using a local RELATIVE_INCLUDE configuration so diagrams can be rendered without internet connectivity.

A practical team policy is:

  • Use a pinned local or standard-library version for CI and published architecture documentation.

  • Use a controlled update process when upgrading the C4-PlantUML library.

  • Avoid silently changing diagram output because an external include changed.


5. Common C4-PlantUML elements

Purpose Macro example
Internal person Person(customer, "Customer", "Description")
External person Person_Ext(partner, "Partner", "Description")
Internal system System(portal, "Customer Portal", "Description")
External system System_Ext(crm, "CRM System", "Description")
Application container Container(api, "Portal API", "Java", "Description")
Database container ContainerDb(db, "Database", "PostgreSQL", "Description")
Internal boundary System_Boundary(system, "System Name") { ... }
Container boundary Container_Boundary(api, "API") { ... }
Relationship Rel(a, b, "Uses", "HTTPS")
Directional relationship Rel_R(a, b, "Uses")
Component Component(service, "Order Service", "Java", "Description")

Relationship labels should describe meaningful behavior, not merely say “connects to.”

Prefer:

Rel(webApp, api, "Retrieves customer orders", "HTTPS/JSON")

Over:

The more useful relationship communicates:

  • The purpose of the interaction

  • The protocol or technology

  • Sometimes the direction or data being exchanged


6. A practical Agile workflow

Step 1: Establish the system boundary

Start with a short workshop involving:

  • Product owner

  • Developers

  • Architect or technical lead

  • Operations representative

  • Relevant external-system owners

Identify:

  • Users

  • Business systems

  • External providers

  • Ownership boundaries

  • Key business responsibilities

Capture the result as a system context diagram.

Step 2: Identify containers

Ask:

  • What runs independently?

  • What is deployed independently?

  • What stores data?

  • What communicates asynchronously?

  • What is owned by another system or team?

Create a container diagram only after the system boundary is understood.

Step 3: Add architectural decisions

For each significant relationship, record decisions such as:

  • Synchronous versus asynchronous integration

  • API style

  • Data ownership

  • Authentication mechanism

  • Failure handling

  • Availability requirements

  • Monitoring responsibility

A diagram should lead to useful conversations, not replace them.

Step 4: Create focused component diagrams

Create a component diagram for a container when a current backlog item needs internal design clarification.

For example:

  • “Add customer support cases.”

  • “Split order processing from the portal API.”

  • “Introduce an event-driven notification flow.”

  • “Replace direct database access with a repository boundary.”

Step 5: Validate with delivery teams

Review the diagrams with the people who build and operate the system. Ask:

  • Does this reflect the actual architecture?

  • Are any boundaries misleading?

  • Are relationships missing?

  • Is a container being confused with a component?

  • Does the diagram reveal an unowned dependency?

  • Will this remain useful after the next increment?

Step 6: Store diagrams with the work

A typical repository layout might be:

architecture/
├── context/
│   └── customer-portal-context.puml
├── containers/
│   └── customer-portal-containers.puml
├── components/
│   └── portal-api-components.puml
├── dynamic/
│   └── submit-support-request.puml
├── deployment/
│   └── customer-portal-production.puml
└── decisions/
    ├── adr-001-api-boundary.md
    └── adr-002-notification-events.md

Keep diagrams versioned with the software whenever possible.


7. Definition of done for an architecture diagram

A diagram is ready when:

  • Its purpose and audience are clear.

  • The scope is stated in the title.

  • The system boundary is unambiguous.

  • Elements have meaningful names.

  • Relationships describe responsibilities or interactions.

  • Technologies are shown where they matter.

  • External systems are distinguished from internal elements.

  • The diagram renders successfully.

  • The delivery team has reviewed it.

  • It is stored in a version-controlled location.

  • It has an owner or review responsibility.

For Agile work, “complete” does not mean “exhaustive.” It means useful, understandable, and sufficiently accurate for the decision at hand.


8. Common beginner mistakes

Modeling infrastructure too early

A context diagram does not need Kubernetes nodes, database tables, or class names. Start with the appropriate abstraction level.

Treating every process as a container

A container should normally represent a major application, service, data store, or independently running unit. A business process inside an API is usually a component or a responsibility, not a container.

Mixing abstraction levels

Avoid placing a class, a database, a business capability, and an external enterprise system on the same diagram unless the purpose is very specific.

Showing technology without responsibility

“Java service” is less useful than:

Order Service — Java/Spring Boot — coordinates order retrieval and order updates.

Using vague relationship labels

Replace “uses” with a meaningful action where possible:

  • “Authenticates with”

  • “Publishes order events to”

  • “Reads customer data from”

  • “Submits support cases to”

  • “Receives payment status from”

Creating diagrams that nobody maintains

An inaccurate architecture diagram is often worse than no diagram. Include diagram updates in the definition of done for architecture-affecting work.

Overusing layout commands

Manual layout can improve readability, but too many positioning commands make diagrams fragile. C4-PlantUML provides layout options such as top-down, left-right, legend, and sketch-style layouts.

Example:

Use layout commands to improve readability, not to encode architectural meaning.


9. A lightweight governance model

For an Agile EA initiative, use lightweight governance:

  • Team level: teams own diagrams for the systems they build.

  • Architecture level: an architecture group reviews cross-team boundaries and significant dependencies.

  • Product level: product owners validate business scope and terminology.

  • Operations level: platform or operations teams validate deployment and support responsibilities.

  • Portfolio level: enterprise architects use system landscape views to identify duplication, strategic dependencies, and modernization candidates.

A useful review cadence is:

  • Context diagrams: review when system scope or ownership changes.

  • Container diagrams: review during major features and architectural changes.

  • Component diagrams: review during implementation of complex capabilities.

  • Deployment diagrams: review when environments, hosting, or operational architecture changes.


10. Recommended starting set

For a beginner’s first Agile EA project, create these three diagrams:

  1. System context diagram
    Shows users, the system, and external dependencies.

  2. Container diagram
    Shows the system’s major applications, services, databases, and message flows.

  3. One focused component diagram
    Shows the internals of the container currently undergoing the most change.

Add dynamic and deployment diagrams only when they answer a specific question.

The main goal is not to produce a large collection of attractive diagrams. It is to create a shared, versioned architectural vocabulary that helps teams deliver change with fewer misunderstandings.

Visual Paradigm C4 Tool: Reference Article List

Based on the search results, here is a curated list of English articles and posts about Visual Paradigm’s C4 modeling capabilities and related AI-powered tools.

  1. From Big Picture to Code: A Beginner’s Guide to Visualizing Software Architecture with the C4 Model: Step-by-step beginner tutorial covering all four C4 levels with practical PayQuick payment platform examples and PlantUML code snippets.

  2. Mastering the AI + C4 Model + Diagram as Code: A Hybrid Approach to Software Architecture Diagrams: Explains why Visual Paradigm remains essential for professional architects and presents a hybrid workflow combining AI, C4, and diagram-as-code.

  3. The Ultimate Guide to C4-PlantUML Studio: Revolutionizing Software Architecture Design: Comprehensive guide covering AI-powered generation, step-by-step workflows, real-world use cases, and why Visual Paradigm leads the market.

  4. Mastering Software Architecture with the C4 Model and Visual Paradigm: Evaluation of Visual Paradigm’s C4 ecosystem including hierarchical navigation, living documentation integration, and practical workflow for linking context to container diagrams.

  5. Architecting Smart Infrastructure: A C4 Model Case Study of an EV Charging Network Using Visual Paradigm’s AI-Powered Tools: Real-world case study demonstrating AI-powered C4 generation for an EV charging network with measurable outcomes.

Leave a Reply