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).

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“.

Written by

Simon Lasselsberger

Founder Lasssim, Software Architecture and Development Expert

Written by

Simon Lasselsberger

Founder Lasssim, Software Architecture and Development Expert

Over the past ten years, I’ve worked with small startups as well as global companies like adidas, helped them implement their business ideas by creating technical plans and by guiding their development teams through projects. The proudest I am about the success we had with Runtastic. They got acquired by adidas in 2015 for €220 million.

Contact me anytime!

SIMON LASSELSBERGER
Software Architecture and Development Expert