Mastering Architecture Visuals: How to Build a C4 System Context Diagram in PlantUML

When designing software systems, communicating high-level boundaries clearly to both technical and non-technical stakeholders is essential. In this masterclass tutorial, we will walk through how to build a professional C4 System Context diagram from scratch using PlantUML inside the free VPasCode editor.

Why Use a Diagram-as-Code Approach for C4 Models?

Traditional drag-and-drop drawing tools often lead to misaligned boxes, inconsistent styling, and tedious manual updates whenever architecture evolves. By leveraging a diagram-as-code tool like a free PlantUML editor, your documentation stays synchronized with code, version-controlled, and clean. Using VPasCode, you get real-time rendering and automatic format detection that makes visualizing software architecture effortless.

The Masterclass Case Study: Online Grocery Store Architecture

To demonstrate how to structure a robust system context diagram, let us look at an Online Grocery Store platform. This architecture needs to capture end-users, external delivery drivers, the core grocery system, and third-party services like payment gateways and logistics providers.

Here is the complete PlantUML source code we will break down step-by-step:

@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
skinparam vpDiagramType C4modelSystemContextDiagram

LAYOUT_TOP_DOWN()
LAYOUT_WITH_LEGEND()

title System Context diagram for Online Grocery Store

Person(customer, "Customer", "Browses the store, orders groceries, and schedules delivery")
Person_Ext(driver, "Delivery Driver", "Delivers orders to customers")

Enterprise_Boundary(grocery_co, "Online Grocery Store") {
  System(grocery_system, "Online Grocery Store System", "Allows customers to order groceries online and manages fulfillment")
}

System_Ext(payment, "Payment Gateway", "Processes card and digital wallet payments")
System_Ext(shipping, "Logistics Provider", "Plans delivery routes and schedules drivers")

Rel(customer, grocery_system, "Browses products and places orders", "HTTPS")
Rel(grocery_system, payment, "Processes payments via", "HTTPS/API")
Rel(grocery_system, shipping, "Creates delivery jobs via", "HTTPS/API")
Rel(driver, grocery_system, "Views delivery assignments", "HTTPS")

@enduml

Step-by-Step Walkthrough of the Code

1. Setting Up the Foundational Environment

I start by initializing the script with standard PlantUML tags and importing the official C4-PlantUML standard library macros. By referencing C4_Context.puml, we unlock semantic elements tailored specifically for system context diagrams.

  • Library Inclusion: !include .../C4_Context.puml loads standard shapes, colors, and styling rules for people, systems, and boundaries.
  • Diagram Typing & Layout: Setting skinparam vpDiagramType C4modelSystemContextDiagram ensures proper integration within VPasCode, while LAYOUT_TOP_DOWN() organizes the visual hierarchy cleanly from top to bottom. I also enable LAYOUT_WITH_LEGEND() to automatically generate a helpful reference guide at the bottom right of the canvas.

2. Defining Actors and Users

Next, I need to define the human actors interacting with our ecosystem. I differentiate between standard system users and external entities using specific C4 macros:

  • The Core User: I create a primary user using Person(customer, "Customer", ...) who initiates orders and browses inventory.
  • The External Actor: I define a delivery driver using Person_Ext(driver, "Delivery Driver", ...) to highlight that while they interact with our fulfillment flow, they exist outside our core internal security perimeter.

3. Establishing Organizational Boundaries and Core Systems

Architectural clarity requires clear boundaries. To encapsulate what our company owns versus what relies on external vendors, I establish an enterprise boundary:

  • Enterprise Boundary: Using Enterprise_Boundary(grocery_co, "Online Grocery Store") creates a dashed container box visually grouping internal infrastructure.
  • Internal System: Inside this boundary, I place our main software asset using System(grocery_system, "Online Grocery Store System", ...).

4. Integrating External Systems

No modern e-commerce platform operates in isolation. I define external dependencies outside the enterprise boundary using specialized external system macros:

  • Payment Processing: System_Ext(payment, "Payment Gateway", ...) represents third-party financial transactions.
  • Logistics & Shipping: System_Ext(shipping, "Logistics Provider", ...) handles route planning and driver assignment.

5. Mapping Relationships and Protocols

To tie the architecture together, I map out directional interactions and communication protocols using the Rel() macro:

  • Customer Flow: Rel(customer, grocery_system, "Browses products and places orders", "HTTPS") illustrates how users connect securely to the core platform.
  • Backend Integrations: I map backend dependencies like payment processing and shipping providers with explicit protocol labels ("HTTPS/API") to give engineers immediate technical context.

Conclusion & Try It Yourself

Building clean software architecture diagrams does not require cumbersome desktop tools or complex file configurations. By combining PlantUML’s powerful C4 syntax with VPasCode, you can write, render, and share architecture diagrams in seconds.

A screenshot of Visual Paradigm VPasCode showing the creation of a C4 System Context Diagram

Ready to try building your own system architecture? Head over to the free VPasCode online editor, paste this code snippet, and watch your diagram render in real time!

Scroll to Top