All posts
MermaidFlowchartArchitectureBest Practices

Mermaid Subgraph Composition: Modular Complex Diagrams

5 min readThe MermaidCreator team

As diagrams grow, they become harder to read. A flat flowchart with 40 nodes is incomprehensible; one organized into logical subgraphs is immediately clear. Mermaid's subgraph composition lets you nest workflows, group related steps, and build diagrams that scale from prototype to production architecture.

Why Subgraphs Matter

A subgraph is a visual and logical boundary—a container for related steps. Use them to:

  • Organize by domain — authentication flows, payment processing, notification delivery as separate sections
  • Hide complexity — show the big picture first, let readers drill into details
  • Reuse patterns — common sub-workflows (retry loops, validation chains) become recognizable at a glance
  • Reason about scope — each subgraph is a unit you can test, document, and own
flowchart TD
    Start([User Action]) --> Auth{Authenticated?}
    
    Auth -->|No| AuthFlow["🔐 Authentication"]
    subgraph AuthFlow["Authentication Flow"]
        A1[Request Credentials]
        A2[Validate]
        A3[Issue Token]
        A1 --> A2 --> A3
    end
    
    Auth -->|Yes| BizFlow["💼 Business Logic"]
    subgraph BizFlow["Process Request"]
        B1[Fetch Data]
        B2[Apply Rules]
        B3[Transform]
        B1 --> B2 --> B3
    end
    
    AuthFlow --> Response["✅ Success"]
    BizFlow --> Response
    Response --> End([Return])

Composition Patterns

Pattern 1: Top-Down Hierarchy

Organize by layers: entry → orchestration → specialized flows.

flowchart TD
    Start([API Request]) --> Validate
    
    subgraph HTTP["HTTP Layer"]
        Validate["Validate Input"]
        Rate["Rate Limit Check"]
        Validate --> Rate
    end
    
    Rate --> Dispatch["Dispatch to Handler"]
    
    subgraph Processing["Processing Layer"]
        Enrich["Enrich Context"]
        Transform["Transform Data"]
        Persist["Persist State"]
        Enrich --> Transform --> Persist
    end
    
    Dispatch --> Enrich
    Persist --> Respond["Send Response"]
    Respond --> End([Done])

Use this for: API handlers, middleware chains, multi-stage pipelines.

Pattern 2: Parallel Subgraphs

Multiple independent workflows that reconverge.

flowchart LR
    Start([Publish Video]) --> Trigger
    
    Trigger -->|Branch 1| Transcoding
    Trigger -->|Branch 2| Thumbnail
    Trigger -->|Branch 3| Metadata
    
    subgraph Transcoding["🎬 Encoding"]
        T1["Queue Job"]
        T2["Transcode"]
        T3["Upload"]
        T1 --> T2 --> T3
    end
    
    subgraph Thumbnail["🖼️ Thumbnail"]
        Th1["Extract Frame"]
        Th2["Optimize"]
        Th1 --> Th2
    end
    
    subgraph Metadata["📝 Metadata"]
        M1["Detect Language"]
        M2["Extract Captions"]
        M1 --> M2
    end
    
    T3 --> Merge["Merge Results"]
    Th2 --> Merge
    M2 --> Merge
    Merge --> Publish["Publish Asset"]

Use this for: concurrent tasks (encoding, indexing, notifications), deployment pipelines with parallel stages.

Pattern 3: Error Handling & Resilience

Subgraphs for retry logic, circuit breakers, and fallbacks.

flowchart TD
    Req["Initiate Request"] --> Call{Call Remote API}
    
    Call -->|Success| Parse["Parse Response"]
    
    Call -->|Failure| Retry
    subgraph Retry["Retry Logic"]
        R1["Wait (exponential)"]
        R2["Attempt"]
        R3{Max Retries?}
        R1 --> R2 --> R3
    end
    
    R3 -->|Retry| R1
    R3 -->|Exhausted| Circuit
    
    subgraph Circuit["Circuit Breaker"]
        C1["Log Failure"]
        C2["Mark Service Down"]
        C3["Serve Stale Cache"]
        C1 --> C2 --> C3
    end
    
    Parse --> Validate["Validate Shape"]
    C3 --> Validate
    Validate --> Success{Valid?}
    Success -->|Yes| End([✅ Complete])
    Success -->|No| Fallback["Use Default"]
    Fallback --> End

Use this for: microservices, external API calls, fault tolerance flows.

Pattern 4: Nested Subgraphs (Multi-Level)

Subgraphs inside subgraphs for highly complex domains.

flowchart TD
    Start([E-commerce Order]) --> CheckStock
    
    subgraph Fulfillment["🛒 Fulfillment"]
        CheckStock["Check Inventory"]
        
        subgraph Inventory["Inventory System"]
            I1["Query DB"]
            I2["Lock Stock"]
            I3["Confirm"]
            I1 --> I2 --> I3
        end
        
        CheckStock --> I1
        I3 --> Pick["Pick Items"]
        
        subgraph Warehouse["Warehouse"]
            W1["Locate Bins"]
            W2["Pick & Scan"]
            W3["QC Check"]
            W1 --> W2 --> W3
        end
        
        Pick --> W1
        W3 --> Pack["Pack Shipment"]
    end
    
    Pack --> Label["Generate Label"]
    Label --> Ship["Hand to Carrier"]
    Ship --> End([Shipped])

Use this for: complex business domains (fulfillment, underwriting, provisioning).

Styling & Clarity

Add emoji to subgraph titles for instant recognition—readers quickly scan for the section they need.

flowchart TD
    User([User]) --> Auth
    
    subgraph Auth["🔐 Auth & Identity"]
        A1[Login]
        A2[MFA]
        A1 --> A2
    end
    
    Auth --> Payment
    
    subgraph Payment["💳 Payment Processing"]
        P1[Validate Card]
        P2[Charge]
        P3[Confirm]
        P1 --> P2 --> P3
    end
    
    Payment --> Notify
    
    subgraph Notify["📧 Notifications"]
        N1[Send Email]
        N2[SMS Alert]
        N1 --> N2
    end
    
    Notify --> End([Success])
    
    style Auth fill:#e1f5ff
    style Payment fill:#fff3e0
    style Notify fill:#f3e5f5

Anti-Patterns to Avoid

  1. Too Many Levels — Three subgraph nesting levels is a hard limit; beyond that, split into separate diagrams.
  2. Mixing Concerns — Don't group unrelated steps just to reduce visual clutter; each subgraph should have one clear purpose.
  3. Subgraph Naming — Use active, descriptive names ("Authentication Flow" not "Auth"), especially for domain-heavy diagrams.
  4. Overuse of Subgraph Styling — Stick to 2–3 distinct colors; too much variety is noise.

When to Reach for Separate Diagrams

If you need:

  • Swimlanes for cross-functional roles (use flowchart with swimlane syntax, not subgraphs)
  • Multiple entry points (use separate diagrams linked in documentation)
  • Recursive flows (each diagram level is a recursion; split into context → detail pairs)

Comparison: Subgraphs vs. Swimlanes

AspectSubgraphSwimlane
NestingYes, multi-levelLimited (role-based rows)
Use caseLogical grouping, layersCross-functional workflows
Visual styleContainer with borderHorizontal lane
ReadabilityBest for modules & scopeBest for actors & responsibility

Subgraphs are for structure (what goes with what); swimlanes are for responsibility (who does what).

Rendering & Export

Build your subgraph-based diagrams in MermaidCreator's visual editor — drag nodes into subgraph groups, and the code generates automatically. Export as PNG or SVG to embed in docs, architecture decision records, or runbooks.

FAQ

Can I link between subgraphs? Yes. Arrows cross subgraph boundaries freely:

subgraph A["Step A"]
    A1[Do Something]
end
subgraph B["Step B"]
    B1[Do Another]
end
A1 --> B1

Should I use subgraph IDs or labels? Always use labels (the second argument in subgraph ID ["Label"]). The label is what readers see; the ID is just internal.

How do I collapse or hide a subgraph in code? Mermaid doesn't natively support collapsing. Create a separate "summary" diagram that shows subgraph names as single nodes, and link to detail diagrams in your docs.

Start with flat flowcharts, then reach for subgraphs when complexity crosses the 15-node threshold. Your future readers will thank you.

Related posts