Software Architecture Diagram Examples

In today’s fast-paced software world, clear communication is key—especially when explaining complex systems through beautiful software architecture diagrams.
This post provides an overview of different types of software architecture diagrams used to illustrate the same web shop system with charts and code. Whether you are creating software architecture diagrams for the first time or looking for the best tool to draw software architecture diagrams online, this overview compares various approaches. Drawing on real-world experiences, we discuss how well-crafted diagrams can bridge the gap between technical and non-technical stakeholders. You’ll see examples using diagrams.net, PlantUML, and the C4 Model (with both Structurizr and PlantUML).
- Example 1 – diagrams.net
- Example 2 – PlantUML Component Diagram
- Example 3 – C4 using Structurizr
- Example 4 – C4 using the default theme
Before we dive into detailed examples, let’s consider a real-world scenario that demonstrates how software architecture diagrams transform complex systems into clear, actionable insights.
The Scenario – A Web Shop
Users can shop through a website or a mobile app. Both interfaces connect to the backend via an API gateway. The backend consists of:
- A microservice for user-related functions with its own database.
- A monolithic application that manages Cart, Inventory, and Shipping using one
database with separate schemas. - An Analytics Service with its own database that exports data to an external
ERP system.
Communication between components uses synchronous API calls and asynchronous
messaging via a message bus.
Goals
The purpose of a Software Architecture Diagram is to clearly communicate an idea, concept, vision, or agreement. Using diagrams helps ensure effective communication and better retention of information. They serve as essential tools to align teams by visually representing complex systems in a straightforward manner.
Furthermore, a great diagram should not only be clear but also beautiful. A visually appealing diagram leverages balanced composition, appropriate whitespace, and a restrained color palette. It includes just enough detail to convey key concepts without overwhelming the viewer, maintaining clarity and focus.
Example 1: diagrams.net is my go-to approach because it works well for these goals for reasonably sized systems, while the other examples show how most of these goals can be reached using different tools.
Example 1 – diagrams.net
I draw software architecture diagrams every day and rely on diagrams.net as my primary tool because it’s convenient, free, online, and works seamlessly with VSCode. It offers exceptional clarity, flexibility, and beauty—making complex systems easy to understand. For a deep dive into my proven techniques and design strategies, check out my course “Communicate efficiently with software architecture diagrams“.
Click the diagrams.net icon in the lower right corner of the diagram to open this diagram in the online version of diagrams.net. Find out more about my styles here.
Example 2 – PlantUML Component Diagram
I’m a huge fan of diagrams as code—the ability to update them programmatically is a major advantage. However, the autolayout almost always fails to produce a diagram that fits my intended storyline and aesthetics because there are very few options to manipulate these aspects. While code-based updates are extremely convenient, the visual appeal and clarity of the diagram and its message may suffer. For structural diagrams, I prefer the manual placement seen in Example 1 over the convenience of code. On the other hand, for class diagrams and sequence diagrams, I love what PlantUML offers.
Here is a diagram of the same web shop system using PlantUML:

@startuml left to right direction hexagon "Website" as web #e17c34 hexagon "Mobile App" as mobile #efc13a hexagon "ERP System" as erp rectangle #line.dashed { hexagon "API Gateway" as gateway #00a6e2 hexagon "Users\nService" as users #48c977 { database "DB" as usersdb #48c977 } hexagon " Analytics\nService" as analytics #965fb3 { database "DB" as analyticsdb #965fb3 } rectangle [] as monolith { hexagon "Cart\nComponent" as cart #48c977 hexagon "Inventory\nComponent" as inventory #48c977 hexagon "Shipping\nComponent" as shipping #48c977 database "DB" as monolithdb #48c977 } queue "Message Bus" as bus #48c977 gateway -[hidden]down- users users -[hidden]down- monolith monolith -[hidden]down- analytics bus .left. users bus .left. analytics bus .left. monolith } web -[#bb3b32]- gateway mobile -[#bb3b32]- gateway cart .. monolithdb inventory .. monolithdb shipping .. monolithdb analytics ---> erp : Data Export legend left |<#e17c34> | Web Client Component | |<#efc13a> | Mobile Client Component | |<#00a6e2> | Gateway Component | |<#48c977> | Backend Component | |<#965fb3> | Analytics Component | |<#b7bbbd> | External Component | endlegend @enduml
Example 3 – C4 using Structurizr
I like the C4 Model for its simplicity and the useful hints it provides—especially at the components (level 2) level. While C4 is an easy-to-learn approach to drawing structural diagrams, it really shines when used with Structurizr. This diagram-as-code tool lets you create a single model of your system and then render different diagrams at any C4 level, maintaining multiple diagrams from one source.
However, Structurizr shares a drawback with PlantUML when it comes to autolayout. As shown, the diagram below looks much nicer than the one in Example 2, but that is due to the manual placement of nodes and connections. Structurizr isn’t as comfortable as diagrams.net for tweaking node positions, label styles, and connection aesthetics—making it sometimes hard to discern what the connections denote. Also, since C4 connections are always directed by default, this can confuse audiences when viewing structural diagrams. (For more insights on this aspect, check out my course “Communicate efficiently with software architecture diagrams“.)
workspace "Getting Started" "This is a model of my software system." { model { properties { "structurizr.groupSeparator" "/" } customer = person "Customer" "A user shopping on the platform" "Actor" webShopSystem = softwareSystem "Web Shop System" "Online shopping platform" { website = container "Website" "Provides shopping functionality to customers" "React" "Webclient" mobileApp = container "Mobile App" "Provides shopping functionality to customers" "React Native" "Mobileclient" group "Backend" { apiGateway = container "API Gateway" "Routes requests to appropriate services" "API Gateway" "Gateway" usersService = container "Users Service" "Handles user management" "Java, Spring Boot" "Backend" usersDb = container "Users Database" "Stores user data" "PostgreSQL" "DatabaseBackend" group "Legacy Monolith" { cartComponent = container "Cart Component" "Manages shopping cart" "Java, Spring" "Backend" inventoryComponent = container "Inventory Component" "Handles product inventory" "Java, Spring" "Backend" shippingComponent = container "Shipping Component" "Manages shipping operations" "Java, Spring" "Backend" monolithDb = container "Monolith Database" "Stores cart, inventory, and shipping data" "PostgreSQL" "DatabaseBackend" } analyticsService = container "Analytics Service" "Processes business analytics" "Python" "Analytics" analyticsDb = container "Analytics Database" "Stores analytics data" "MongoDB" "DatabaseAnalytics" messageBus = container "Message Bus" "Handles async communication" "RabbitMQ" "MessagebusBackend" } } erp = softwareSystem "ERP System" "External enterprise system" "External" # relationships customer -> website "Uses" "HTTPS" "Other" customer -> mobileApp "Uses" "HTTPS" "Other" website -> apiGateway "Makes API calls to" "HTTPS" "HTTPS" mobileApp -> apiGateway "Makes API calls to" "HTTPS" "HTTPS" apiGateway -> usersService "Routes to" "HTTPS" "HTTP" apiGateway -> cartComponent "Routes to" "HTTPS" "HTTP" apiGateway -> inventoryComponent "Routes to" "HTTPS" "HTTP" apiGateway -> shippingComponent "Routes to" "HTTPS" "HTTP" apiGateway -> analyticsService "Routes to" "HTTPS" "HTTP" usersService -> usersDb "Reads/Writes" "Other" "Other" cartComponent -> monolithDb "Reads/Writes" "Other" "Other" inventoryComponent -> monolithDb "Reads/Writes" "Other" "Other" shippingComponent -> monolithDb "Reads/Writes" "Other" "Other" analyticsService -> analyticsDb "Reads/Writes" "Other" "Other" usersService -> messageBus "Publishes/Subscribes" "Other" "Other" cartComponent -> messageBus "Publishes/Subscribes" "Ohter" "Other" inventoryComponent -> messageBus "Publishes/Subscribes" "Other" "Other" shippingComponent -> messageBus "Publishes/Subscribes" "Other" "Other" analyticsService -> messageBus "Publishes/Subscribes" "Other" "Other" analyticsService -> erp "Exports data to" "HTTPS" "HTTPS" } views { systemContext webShopSystem { include * autolayout lr } container webShopSystem { include * exclude "apiGateway -> *" } component analyticsService { include * autolayout lr } theme default styles { element "Backend" { background #48c977 shape Hexagon description false metadata false fontSize 40 } element "DatabaseBackend" { shape Cylinder background #48c977 description false metadata false fontSize 40 } element "Analytics" { background #965fb3 shape Hexagon description false metadata false fontSize 40 } element "DatabaseAnalytics" { shape Cylinder background #965fb3 description false metadata false fontSize 40 } element "MessagebusBackend" { shape Pipe background #48c977 description false metadata false fontSize 40 } element "Gateway" { background #00a6e2 shape Hexagon description false metadata false fontSize 40 } element "Webclient" { background #e17c34 shape Hexagon description false metadata false fontSize 40 } element "Mobileclient" { background #efc13a shape Hexagon description false metadata false fontSize 40 } relationship HTTPS { color #bb3b32 style solid routing Orthogonal fontSize 40 } relationship Other { style dotted routing Orthogonal fontSize 40 } element Actor { background #e14d43 description false metadata false fontSize 40 } element "External" { background #b7bbbd shape Hexagon description false metadata false fontSize 40 } } } configuration { scope softwaresystem } }
Example 4 – C4 using the default theme
If you are happy with the default blue theme of C4 and comfortable with autolayout, then you have two really good options: using PlantUML with the C4 extension, or Structurizr with its default theme. I always advocate focusing on your audience—if they are accustomed to C4, stick with it.
However, if you feel an urge to improve diagram clarity, consider experimenting with alternative themes (as shown above) or check out my course “Communicate efficiently with software architecture diagrams” for my 12 tool-independent guidelines on producing beautiful diagrams quickly.
C4 PlantUML

@startuml !include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml left to right direction LAYOUT_WITH_LEGEND() AddElementTag("service", $shape=EightSidedShape(), $bgColor="CornflowerBlue", $fontColor="white", $legendText="micro serviceneight sided") Person_Ext(customer, "Customer", "A user shopping on the platform") Container(website, "Website", "React", "Provides shopping functionality to customers") Container(mobile_app, "Mobile App", "React Native", "Provides shopping functionality to customers") System_Boundary(shop, "Backend") { Container(api_gateway, "API Gateway", "API Gateway", "Routes requests to appropriate services") Container(users_service, "Users Service", "Java, Spring Boot", "Handles user management") ContainerDb(users_db, "Users Database", "PostgreSQL", "Stores user data") Boundary(monolith_boundary, "Legacy Monolith") { Container(cart_component, "Cart Component", "Java, Spring", "Manages shopping cart") Container(inventory_component, "Inventory Component", "Java, Spring", "Handles product inventory") Container(shipping_component, "Shipping Component", "Java, Spring", "Manages shipping operations") ContainerDb(monolith_db, "Monolith Database", "PostgreSQL", "Stores cart, inventory, and shipping data") } Container(analytics_service, "Analytics Service", "Python", "Processes business analytics") ContainerDb(analytics_db, "Analytics Database", "MongoDB", "Stores analytics data") Container(message_bus, "Message Bus", "RabbitMQ", "Handles async communication") } System_Ext(erp, "ERP System", "External enterprise system") Rel(customer, website, "Uses", "HTTPS") Rel(customer, mobile_app, "Uses", "HTTPS") Rel(website, api_gateway, "Makes API calls to", "HTTPS") Rel(mobile_app, api_gateway, "Makes API calls to", "HTTPS") Rel(api_gateway, users_service, "Routes to", "HTTPS") Rel(api_gateway, cart_component, "Routes to", "HTTPS") Rel(api_gateway, inventory_component, "Routes to", "HTTPS") Rel(api_gateway, shipping_component, "Routes to", "HTTPS") Rel(api_gateway, analytics_service, "Routes to", "HTTPS") Rel(users_service, users_db, "Reads/Writes") Rel(cart_component, monolith_db, "Reads/Writes") Rel(inventory_component, monolith_db, "Reads/Writes") Rel(shipping_component, monolith_db, "Reads/Writes") Rel(analytics_service, analytics_db, "Reads/Writes") Rel(users_service, message_bus, "Publishes/Subscribes") Rel(cart_component, message_bus, "Publishes/Subscribes") Rel(inventory_component, message_bus, "Publishes/Subscribes") Rel(shipping_component, message_bus, "Publishes/Subscribes") Rel(analytics_service, message_bus, "Publishes/Subscribes") Rel(analytics_service, erp, "Exports data to", "HTTPS") @enduml
C4 Structurizr
workspace "Getting Started" "This is a model of my software system." { model { properties { "structurizr.groupSeparator" "/" } customer = person "Customer" "A user shopping on the platform" "Actor" webShopSystem = softwareSystem "Web Shop System" "Online shopping platform" { website = container "Website" "Provides shopping functionality to customers" "React" "Webclient" mobileApp = container "Mobile App" "Provides shopping functionality to customers" "React Native" "Mobileclient" group "Backend" { apiGateway = container "API Gateway" "Routes requests to appropriate services" "API Gateway" "Gateway" usersService = container "Users Service" "Handles user management" "Java, Spring Boot" "Backend" usersDb = container "Users Database" "Stores user data" "PostgreSQL" "DatabaseBackend" group "Legacy Monolith" { cartComponent = container "Cart Component" "Manages shopping cart" "Java, Spring" "Backend" inventoryComponent = container "Inventory Component" "Handles product inventory" "Java, Spring" "Backend" shippingComponent = container "Shipping Component" "Manages shipping operations" "Java, Spring" "Backend" monolithDb = container "Monolith Database" "Stores cart, inventory, and shipping data" "PostgreSQL" "DatabaseBackend" } analyticsService = container "Analytics Service" "Processes business analytics" "Python" "Analytics" analyticsDb = container "Analytics Database" "Stores analytics data" "MongoDB" "DatabaseAnalytics" messageBus = container "Message Bus" "Handles async communication" "RabbitMQ" "MessagebusBackend" } } erp = softwareSystem "ERP System" "External enterprise system" "External" # relationships customer -> website "Uses" "HTTPS" "Other" customer -> mobileApp "Uses" "HTTPS" "Other" website -> apiGateway "Makes API calls to" "HTTPS" "HTTPS" mobileApp -> apiGateway "Makes API calls to" "HTTPS" "HTTPS" apiGateway -> usersService "Routes to" "HTTPS" "HTTP" apiGateway -> cartComponent "Routes to" "HTTPS" "HTTP" apiGateway -> inventoryComponent "Routes to" "HTTPS" "HTTP" apiGateway -> shippingComponent "Routes to" "HTTPS" "HTTP" apiGateway -> analyticsService "Routes to" "HTTPS" "HTTP" usersService -> usersDb "Reads/Writes" "Other" "Other" cartComponent -> monolithDb "Reads/Writes" "Other" "Other" inventoryComponent -> monolithDb "Reads/Writes" "Other" "Other" shippingComponent -> monolithDb "Reads/Writes" "Other" "Other" analyticsService -> analyticsDb "Reads/Writes" "Other" "Other" usersService -> messageBus "Publishes/Subscribes" "Other" "Other" cartComponent -> messageBus "Publishes/Subscribes" "Ohter" "Other" inventoryComponent -> messageBus "Publishes/Subscribes" "Other" "Other" shippingComponent -> messageBus "Publishes/Subscribes" "Other" "Other" analyticsService -> messageBus "Publishes/Subscribes" "Other" "Other" analyticsService -> erp "Exports data to" "HTTPS" "HTTPS" } views { systemContext webShopSystem { include * autolayout lr } container webShopSystem { include * exclude "apiGateway -> *" } container webShopSystem { include * autolayout lr } component analyticsService { include * autolayout lr } theme default styles { element "DatabaseBackend" { shape Cylinder } element "DatabaseAnalytics" { shape Cylinder } element "MessagebusBackend" { shape Pipe } } } configuration { scope softwaresystem } }
Conclusion
In conclusion, these examples show that there is no one-size-fits-all tool for creating effective software architecture diagrams. Whether you choose diagrams.net for its flexibility, PlantUML for code-based diagrams, or Structurizr for maintaining a single, unified model, your choice should be driven by your audience and project needs. Experiment with different approaches to find the balance between clarity, aesthetics, and ease of updates.
For more in-depth techniques and my 12 tool-independent guidelines on producing beautiful diagrams, check out my course “Communicate efficiently with software architecture diagrams“.