All posts
MermaidArchitectureDependenciesSoftware DesignVisualization

Mermaid dependency graphs: visualize software architecture and component dependencies

6 min readThe MermaidCreator team

Understanding how your components depend on each other is critical for maintainability, refactoring, and system design. Dependency graphs—directed diagrams showing which modules, services, or libraries depend on which—help teams visualize the connections that often stay hidden in code. Mermaid makes it easy to create clear, version-controllable dependency graphs using its graph syntax.

Why dependency visualization matters

Dependencies shape your codebase's architecture. Without a clear picture, you risk:

  • Circular dependencies that make refactoring impossible
  • Tight coupling between distant modules, increasing fragility
  • Hidden transitive dependencies that break when an indirect upstream module changes
  • Unclear separation of concerns when layers blur together
  • Painful onboarding when new team members can't see the big picture

Dependency graphs turn complexity into clarity, surfacing the architectural decisions you've made (or accidentally inherited).

Dependency graph syntax in Mermaid

Mermaid's graph syntax is ideal for dependencies: nodes are modules or services, and edges show "depends on" relationships.

graph TD
    A["Frontend App<br/>React + TypeScript"]
    B["API Client<br/>Axios + Redux"]
    C["REST API<br/>Node.js + Express"]
    D["Database<br/>PostgreSQL"]
    E["Cache<br/>Redis"]
    F["Auth Service<br/>JWT + Passport"]
    
    A --> B
    B --> C
    C --> D
    C --> E
    C --> F
    B --> F

Each arrow points "downward" to a dependency: "A depends on B" means A cannot function without B. This creates a dependency tree where leaf nodes (with no outgoing edges) have no dependencies themselves.

Real-world example: microservices architecture

Here's a typical e-commerce system with multiple services:

graph TD
    Client["🌐 Web Client<br/>React + Redux"]
    Mobile["📱 Mobile App<br/>React Native"]
    
    Gateway["API Gateway<br/>Kong"]
    
    Auth["🔐 Auth Service<br/>OAuth 2.0"]
    User["👤 User Service<br/>Microservice"]
    Product["🛍️ Product Service<br/>Microservice"]
    Order["📦 Order Service<br/>Microservice"]
    Payment["💳 Payment Service<br/>Microservice"]
    Notification["🔔 Notification Service<br/>Queue + Workers"]
    
    UserDB["User DB<br/>PostgreSQL"]
    ProductDB["Product DB<br/>PostgreSQL"]
    OrderDB["Order DB<br/>PostgreSQL"]
    Cache["Cache Layer<br/>Redis"]
    Queue["Message Queue<br/>RabbitMQ"]
    
    Client --> Gateway
    Mobile --> Gateway
    
    Gateway --> Auth
    Gateway --> User
    Gateway --> Product
    Gateway --> Order
    Gateway --> Payment
    
    User --> UserDB
    User --> Cache
    Product --> ProductDB
    Product --> Cache
    Order --> OrderDB
    Order --> Cache
    Order --> Queue
    
    Payment --> Queue
    Auth --> UserDB
    
    Queue --> Notification
    Notification --> Cache

This diagram shows:

  • Two client types depend on the API Gateway
  • Gateway routes to five services (auth, user, product, order, payment)
  • Each service owns its database (database-per-service pattern)
  • Shared cache layer for performance
  • Message queue for async operations
  • Notification service consumes from the queue

Advanced: highlighting dependency layers

For larger systems, color-code dependencies by layer to show architectural tiers:

graph TD
    subgraph Presentation["🖥️ Presentation Layer"]
        Web["Web UI"]
        Mobile["Mobile App"]
    end
    
    subgraph API["🔌 API Layer"]
        Gateway["API Gateway"]
    end
    
    subgraph Business["💼 Business Logic"]
        Auth["Auth Service"]
        Order["Order Service"]
        Inventory["Inventory Service"]
    end
    
    subgraph Data["🗄️ Data Layer"]
        AuthDB["Auth DB"]
        OrderDB["Order DB"]
        InventoryDB["Inventory DB"]
        Cache["Cache"]
    end
    
    subgraph External["🌍 External"]
        PaymentGW["Payment Gateway"]
        Email["Email Service"]
    end
    
    Web --> Gateway
    Mobile --> Gateway
    
    Gateway --> Auth
    Gateway --> Order
    Gateway --> Inventory
    
    Auth --> AuthDB
    Auth --> Cache
    Order --> OrderDB
    Order --> Cache
    Order --> PaymentGW
    Inventory --> InventoryDB
    Inventory --> Cache
    
    Order --> Email

Each subgraph represents a tier; arrows cross tiers cleanly. This makes it obvious which layers can talk to which (presentation speaks only to API; API speaks to business; business speaks to data and external services).

Identifying and fixing problematic dependencies

Common dependency issues appear visually:

IssueWhat it looks likeFix
Circular dependencyA → B → A (a loop)Introduce an abstraction layer or message queue
Tight couplingA → B and A → C and B → C (many arrows)Extract shared logic into a library; use interfaces
Implicit transitive depA → B → D, but A also uses D directlyMake the dependency explicit (A → D) or use B's API only
Layer violationPresentation layer connects directly to Data layerRoute through API/Business layer
God serviceOne service connects to everythingSplit into smaller, focused services; use facade pattern

For example, a cycle (Auth → User → Auth) indicates design confusion. Resolve by:

  1. Moving shared logic to a third module
  2. Having both depend on that module instead of each other
  3. Using callbacks or events to break the cycle

Frontend dependencies: libraries and modules

Dependency graphs also work great for frontend architecture:

graph TD
    App["App Component<br/>Root"]
    Store["Redux Store"]
    UI["UI Component Library<br/>Shadcn"]
    Form["Form Handling<br/>React Hook Form"]
    Fetch["Data Fetching<br/>TanStack Query"]
    
    Pages["Page Components<br/>Dashboard, Settings"]
    
    App --> Store
    App --> Pages
    App --> UI
    Pages --> Form
    Pages --> Fetch
    Form --> UI
    Fetch --> Store
    Fetch --> UI

This shows:

  • App is the root, depends on Store, Pages, and UI
  • Pages depend on Form, Fetch, and (indirectly) UI
  • Form and Fetch both depend on UI and Store
  • Store is a hub; many modules depend on it

Best practices for dependency graphs

  1. One direction only — Agree on whether edges point from dependant to dependency (A → B means "A depends on B") or vice versa. Mermaid doesn't enforce direction, so be consistent.
  2. Group related dependencies — Use subgraphs to cluster services by tier, team, or domain.
  3. Avoid too many edges — If your graph is a dense hairball, your architecture is too coupled. Refactor first, then draw.
  4. Label edges for complex relationships — Use edge labels to clarify "depends on," "calls," "publishes to," etc.
  5. Keep it updated — Dependency graphs rot. Make updating it part of your code review process (e.g., "If you add a new service dependency, update the diagram").
  6. Use in documentation — Commit your dependency graph in your repo's README or architecture docs; version it like code.

Comparing dependency graphs to other diagrams

WhenWhat to use
Showing which services depend on whichDependency graph (this post)
Showing how data flows at runtimeSankey diagram or sequence diagram
Showing the build pipelineFlowchart or CI/CD pipeline
Showing request/response over timeSequence diagram
Showing system layersBlock diagram or dependency graph with subgraphs

FAQ

How do I detect cycles in my dependencies?
Look for closed loops in your diagram (A → B → C → A). If you see any, your architecture has a cycle—trace the path in code and refactor to break it. Consider using automated tools like npm-check-circular for Node.js or pydepend for Python.

Should I include all dependencies or just direct ones?
Start with direct dependencies only; your diagram stays readable. If you need transitive dependencies (A → B → D), you can add them with different arrow styles (dashed vs. solid).

Can I auto-generate dependency graphs from code?
Yes. Tools like ts-graph (TypeScript), pydepend (Python), and depcheck (JavaScript) analyze your code and export dependency data. You can convert that to Mermaid format programmatically—great for keeping diagrams in sync with reality.

What's the difference between a dependency graph and an UML class diagram?
A UML class diagram shows relationships between classes (inheritance, composition, association). A dependency graph shows relationships between modules or services (which one depends on the other at runtime). They work at different levels of abstraction.

Map your architecture with dependency graphs in the MermaidCreator editor. Clear dependencies lead to modular, maintainable systems that teams can reason about.

Related posts