Overview

C4 (Context, Container, Component, Code) diagrams visualize software architecture at different levels of abstraction. Sirena renders C4 diagrams with the element types, boundaries, and relationships shown below.

Supported C4 Levels

  • C4Context - System Context diagrams showing the big picture

  • C4Container - Container diagrams showing high-level technology choices

  • C4Component - Component diagrams showing components within containers

  • C4Dynamic - Dynamic diagrams showing runtime behavior

  • C4Deployment - Deployment diagrams showing infrastructure mapping

Basic Usage

Simple C4 Context Diagram

C4Context
    title System Context for Banking System
    Person(customer, "Customer", "A bank customer")
    System(banking, "Banking System", "Core banking application")
    System_Ext(email, "Email System", "External email service")

    Rel(customer, banking, "Uses")
    Rel(banking, email, "Sends emails", "SMTP")

This creates a context diagram showing:

  • A person (customer) interacting with the system

  • The main banking system

  • An external email system

  • Relationships between components

C4 Container Diagram

C4Container
    title Container Diagram for Banking System

    Person(customer, "Customer", "A bank customer")

    Container(web, "Web Application", "React", "Customer-facing web app")
    Container(api, "API", "Node.js", "Backend REST API")
    ContainerDb(db, "Database", "PostgreSQL", "Stores customer data")

    Rel(customer, web, "Uses", "HTTPS")
    Rel(web, api, "Calls", "REST/JSON")
    Rel(api, db, "Reads/Writes", "SQL")

Element Types

People

Person

Represents a user of the system.

C4Context
    Person(user, "User", "A system user")

Where:

  • user - Unique identifier

  • "User" - Display label

  • "A system user" - Description

Person_Ext

Represents an external user outside the system boundary.

C4Context
    Person_Ext(external, "External User", "Outside the organization")

Systems

System

Represents a software system.

C4Context
    System(app, "Application", "Main application system")

System_Ext

Represents an external system.

C4Context
    System_Ext(crm, "CRM System", "Third-party CRM")

SystemDb

Represents a database system.

C4Context
    SystemDb(maindb, "Main Database", "Central data store")

SystemDb_Ext

Represents an external database.

C4Context
    SystemDb_Ext(legacy, "Legacy DB", "Old system database")

SystemQueue

Represents a message queue system.

C4Context
    SystemQueue(queue, "Message Queue", "Event processing")

SystemQueue_Ext

Represents an external queue system.

C4Context
    SystemQueue_Ext(kafka, "Kafka", "External event stream")

Containers

Container

Represents an application or service container.

C4Container
    Container(web, "Web App", "React", "Frontend application")

Where:

  • web - Unique identifier

  • "Web App" - Display label

  • "React" - Technology stack

  • "Frontend application" - Description

ContainerDb

Represents a database container.

C4Container
    ContainerDb(db, "Database", "PostgreSQL", "Data persistence")

ContainerQueue

Represents a message queue container.

C4Container
    ContainerQueue(mq, "Queue", "RabbitMQ", "Async messaging")

Components

Component

Represents a component within a container.

C4Component
    Component(ctrl, "Controller", "REST Controller", "Handles HTTP requests")

Relationships

Basic Relationship

Use Rel() to show a directional relationship:

C4Context
    Person(user, "User")
    System(app, "App")
    Rel(user, app, "Uses")

Parameters:

  • Source element ID

  • Target element ID

  • Relationship label

  • Technology (optional)

Example 1. Example with technology
Rel(web, api, "Calls API", "REST/HTTPS")

Bidirectional Relationship

Use BiRel() for two-way relationships:

C4Context
    System(app1, "App 1")
    System(app2, "App 2")
    BiRel(app1, app2, "Syncs data")

Boundaries

Boundaries group related elements together.

Enterprise Boundary

Groups systems within an enterprise.

C4Context
    Enterprise_Boundary(org, "Our Organization") {
        System(app1, "App 1")
        System(app2, "App 2")
    }

System Boundary

Groups containers within a system.

C4Container
    System_Boundary(sys, "Banking System") {
        Container(web, "Web App", "React")
        Container(api, "API", "Node.js")
    }

Custom Boundary

Generic boundary with custom type.

C4Context
    Boundary(custom, "Custom Group", "boundary") {
        System(s1, "System 1")
        System(s2, "System 2")
    }

Nested Boundaries

Boundaries can be nested for hierarchical organization:

C4Context
    Enterprise_Boundary(org, "Organization") {
        System_Boundary(sys, "System") {
            Boundary(module, "Module", "boundary") {
                System(app, "Application")
            }
        }
    }

Element Attributes

Sprite Icons

Add custom icons to elements:

C4Context
    Person(user, "User", "Description", $sprite="person_icon")

Add clickable links:

C4Context
    System(app, "App", "Description", $link="https://example.com")

Tags

Add tags for categorization:

C4Context
    System(app, "App", "Description", $tags="critical,production")

Combined Attributes

Multiple attributes can be combined:

C4Container
    Container(web, "Web App", "React", "Frontend",
              $sprite="react", $link="https://app.example.com",
              $tags="frontend,critical")

Layout Configuration

Configure diagram layout using UpdateLayoutConfig():

C4Context
    UpdateLayoutConfig($c4ShapeInRow=3, $c4BoundaryInRow=2)

    Person(user, "User")
    System(app, "App")

Complete Example

Example 2. Full C4 Context Diagram with Nested Boundaries
C4Context
    title Internet Banking System Context

    Enterprise_Boundary(bank, "Bank Boundary") {
        Person(customer, "Customer", "Bank customer with accounts")

        System_Boundary(core, "Core Banking") {
            System(banking, "Banking System", "Main application")
            SystemDb(db, "Database", "Customer and account data")
        }

        System_Ext(email, "Email System", "Microsoft Exchange")
    }

    System_Ext(mainframe, "Mainframe", "Legacy system")

    BiRel(customer, banking, "Uses")
    Rel(banking, db, "Reads/Writes", "SQL")
    Rel(banking, email, "Sends emails", "SMTP")
    Rel(banking, mainframe, "Gets data", "XML/HTTPS")

This creates a hierarchical diagram showing:

  • Enterprise boundary containing the bank’s systems

  • System boundary for core banking components

  • Internal and external systems

  • Database and email integration

  • Bidirectional and unidirectional relationships

Visual Styling

Colors and Sizes

Element colors come from the active theme and element boxes are sized from their text, so the exact colors and dimensions are not fixed values.

Implementation Details

Architecture

C4 diagrams are implemented using the 6-file Parslet architecture:

  1. Diagram::C4 - Data model with elements, boundaries, relationships

  2. Parser::Grammars::C4 - Parslet grammar for C4 syntax

  3. Parser::Builders::C4 - Parse tree to diagram model builder

  4. Parser::C4 - Main parser class

  5. Layout::C4 - Diagram to graph layout

  6. Renderer::C4 - SVG renderer

Layout::C4 positions elements with the fallback grid; layout_engine: :elk is not available for C4.

Rendering Pipeline

The C4 rendering pipeline:

  1. Parse - Convert Mermaid source to C4 model

  2. Graph - Convert to graph structure with positions

  3. Layout - Calculate positions for elements and boundaries

  4. Render - Generate SVG with C4 styling

Limitations

  • Variable syntax (${macroName}) has limited support

  • Some test-specific constructs may not parse (sprites, links, tags)

  • Layout is a fallback grid, not the hierarchical ELK layout this page previously described

  • Oracle-valid corpus coverage: 11/11 passing (100.0%).

  • Outside the compatibility denominator: 16/22 artifact cases currently render; 1/14 invalid cases currently render.

  • Generated from scoreboard/corpus.json by bundle exec rake docs:compatibility.

Troubleshooting

Common Issues

Parse Errors

Issue: "Syntax error at line X"

Solution: Check for:

  • Proper element syntax: Type(id, "label", "desc")

  • Matching braces in boundaries

  • Comma-separated parameters

  • Quoted strings for labels and descriptions

Missing Elements

Issue: Elements don’t appear in output

Solution: Verify:

  • Element IDs are unique

  • Elements are within boundaries if nested

  • Relationships reference existing element IDs

Layout Issues

Issue: Elements overlap or poorly positioned

Solution:

  • Use boundaries to organize elements

  • Limit elements per diagram

  • Consider using UpdateLayoutConfig() for fine-tuning

Getting Help

For issues not covered here:

  • Check examples in spec/mermaid/c4/

  • Review source code comments

  • Submit bug reports with minimal reproducible examples


Back to top

Copyright © 2025 Ribose. Sirena is open source under the BSD-2-Clause license.

This site uses Just the Docs, a documentation theme for Jekyll.