返回文章列表
c4 modelmermaidsoftware architecturecomponent diagramarchitecture diagrams

Drawing C4 Model Diagrams with Mermaid: A Practical Guide for Software Architects

Site Team 5 min read

You know that feeling when someone asks you to "document the architecture" and you end up spending half a day in a drawing tool moving boxes around? I've been there. Then I discovered you can write C4 diagrams in Mermaid, and suddenly architecture documentation became something I didn't dread.

What's the C4 Model Anyway?

Simon Brown created the C4 model back around 2006-2011. The idea is simple: show your software architecture at four zoom levels, like Google Maps but for code.

The four levels are:

  • Context - The big picture. Who uses your system? What other systems does it talk to?
  • Container - The major building blocks. Your API, database, web app - the stuff that runs.
  • Component - What's inside each container. The services, controllers, repositories.
  • Code - Class diagrams. Most teams skip this level honestly.
  • The beauty is you pick the right level for your audience. Talking to a product manager? Show them Context. Onboarding a new dev? Container and Component.

    Your First C4 Context Diagram

    Let's build something real. Say you're documenting an e-commerce system:

    C4Context
        title System Context for E-Commerce Platform
    

    Person(customer, "Customer", "A user who browses and purchases products")
    Person(admin, "Admin", "Manages products and orders")

    System(ecommerce, "E-Commerce Platform", "Allows customers to browse products and place orders")

    System_Ext(payment, "Payment Gateway", "Handles payment processing")
    System_Ext(shipping, "Shipping Service", "Manages delivery logistics")
    System_Ext(email, "Email Service", "Sends notifications")

    Rel(customer, ecommerce, "Browses, purchases")
    Rel(admin, ecommerce, "Manages products/orders")
    Rel(ecommerce, payment, "Processes payments")
    Rel(ecommerce, shipping, "Creates shipments")
    Rel(ecommerce, email, "Sends emails")

    That's it. No dragging boxes. No fighting with arrow alignment. Just text that describes what you mean.

    The syntax is pretty intuitive:

    • Person() for users

    • System() for your system

    • System_Ext() for external systems

    • Rel() for relationships


    Diving Deeper: Container Diagrams

    When you need to show what's actually running, use C4Container:

    C4Container
        title Container Diagram for E-Commerce Platform
    

    Person(customer, "Customer", "")

    Container_Boundary(ecommerce, "E-Commerce Platform") {
    Container(web, "Web Application", "React", "Serves the storefront UI")
    Container(api, "API Gateway", "Node.js", "Handles all API requests")
    Container(orders, "Order Service", "Python", "Processes orders")
    Container(catalog, "Catalog Service", "Go", "Manages products")
    ContainerDb(db, "Database", "PostgreSQL", "Stores all data")
    ContainerQueue(queue, "Message Queue", "RabbitMQ", "Async processing")
    }

    System_Ext(payment, "Payment Gateway", "")

    Rel(customer, web, "Uses", "HTTPS")
    Rel(web, api, "Calls", "REST")
    Rel(api, orders, "Routes to")
    Rel(api, catalog, "Routes to")
    Rel(orders, db, "Reads/Writes")
    Rel(orders, queue, "Publishes events")
    Rel(orders, payment, "Processes payment")

    Now anyone can see the tech stack at a glance. React frontend, Node.js gateway, microservices in Python and Go, PostgreSQL for storage. No guessing.

    Component Diagrams: The Developer's View

    This is where new team members really benefit. What's actually inside that Order Service?

    C4Component
        title Component Diagram for Order Service
    

    Container(api, "API Gateway", "", "")
    ContainerDb(db, "Database", "", "")
    ContainerQueue(queue, "Message Queue", "", "")
    System_Ext(payment, "Payment Gateway", "")

    Container_Boundary(orders, "Order Service") {
    Component(controller, "Order Controller", "FastAPI", "Handles HTTP requests")
    Component(service, "Order Service", "Python", "Business logic for orders")
    Component(repo, "Order Repository", "SQLAlchemy", "Data access layer")
    Component(events, "Event Publisher", "Pika", "Publishes order events")
    Component(payment_client, "Payment Client", "httpx", "Integrates with payment")
    }

    Rel(api, controller, "HTTP/JSON")
    Rel(controller, service, "Uses")
    Rel(service, repo, "Uses")
    Rel(service, events, "Uses")
    Rel(service, payment_client, "Uses")
    Rel(repo, db, "SQL")
    Rel(events, queue, "AMQP")
    Rel(payment_client, payment, "HTTPS")

    A new developer can look at this and immediately understand the codebase structure. Controller handles requests, service has business logic, repository talks to the database. Standard patterns, clearly visualized.

    Gotchas I Learned the Hard Way

    C4 support in Mermaid is still experimental. Here's what tripped me up:

    Layout is tricky. Mermaid doesn't have smart auto-layout for C4 diagrams. The order you write statements affects positioning. If your diagram looks weird, try reordering the element definitions. Keep it simple. Don't try to cram everything into one diagram. That 50-microservice architecture? Break it into multiple focused diagrams. Styling is limited. You can tweak colors with UpdateElementStyle(), but don't expect pixel-perfect control. That's fine - the point is communication, not art. Use $ for named parameters. When styling, write UpdateRelStyle(a, b, $offsetX="-40") with the dollar sign prefix. Took me too long to figure that out.

    Why Bother with C4 in Mermaid?

    I asked myself this when I could just use dedicated tools like Structurizr. Here's what sold me:

    It lives with the code. Put your C4 diagrams in your repo's docs folder. They get version controlled. They show up in pull request reviews. When the code changes, you see the diagram change too. GitHub renders it. Drop a C4 diagram in your README, and GitHub shows it. No external links, no embedded images that get stale. Lower barrier. Everyone on the team can update it. No special tool licenses. No "I don't have draw.io installed." Just edit text. It's fast. Once you know the syntax, you can diagram a new service in five minutes. Try that in a visual editor.

    When to Use Something Else

    Being honest here: Mermaid C4 isn't always the right choice.

    For complex enterprise architecture with dozens of systems, Structurizr gives you better tooling. For diagrams that need to look polished for presentations, you might want draw.io or Figma.

    But for day-to-day architecture documentation that actually gets maintained? Mermaid hits the sweet spot.

    Getting Started Today

    Next time you need to explain how your system works:

  • Start with a Context diagram - just the users and external systems
  • Add a Container diagram for the technical overview
  • Create Component diagrams for the parts that need explaining
  • Keep them in your repo. Update them when things change. You'll be amazed how much easier architecture discussions become when everyone's looking at the same picture.

    References

  • C4 Model Official Site - Simon Brown's complete C4 model documentation
  • Mermaid C4 Diagram Syntax - Official Mermaid C4 documentation
  • InfoQ: The C4 Model for Software Architecture - In-depth article on C4 adoption
  • Building C4 Diagrams in Mermaid - Practical tutorial with examples
  • freeCodeCamp: Software Architecture Diagrams Using C4 - Beginner-friendly guide
  • 分享这篇文章