Skip to content

Dependency Graph Enforcement

What you'll learn

  • Visualizing package dependencies across your monorepo
  • Defining and enforcing layered dependency rules
  • Detecting circular dependencies before they cause build issues
  • Integrating graph checks into CI as a quality gate

Prerequisites

  • An existing Archipelago monorepo (see Monorepo Scaffolding)
  • The dependency_graph command generated in your monorepo toolkit
  • Graphviz installed for visualization (brew install graphviz on macOS)

Step 1: Generate the Dependency Graph Command

bash
archipelago generate dependency_graph

You will be prompted for:

  • appName — Your app name (e.g., MyApp)
  • enableEnforcement — Whether to enforce layer rules (true)

Step 2: Visualize Your Dependencies

Generate a visual graph of all package relationships:

bash
# Output as DOT format
dart run devtools dependency_graph --format dot > deps.dot

# Render to PNG
dot -Tpng deps.dot -o deps.png

# Or output as text tree
dart run devtools dependency_graph --format tree

Example tree output:

app
├── feature_auth
│   ├── core_network
│   │   └── core_common
│   └── core_storage
│       └── core_common
├── feature_home
│   └── core_network
│       └── core_common
└── app_debugger_impl
    └── core_common

Step 3: Define Layer Rules

Create dependency_rules.yaml in your monorepo root to enforce architectural boundaries:

yaml
layers:
  - name: app
    packages:
      - app
    can_depend_on: [feature, core, shared]

  - name: feature
    packages:
      - packages/feature_*
    can_depend_on: [core, shared]

  - name: core
    packages:
      - packages/core_*
    can_depend_on: [shared]

  - name: shared
    packages:
      - packages/shared_*
    can_depend_on: []

banned:
  - from: packages/feature_*
    to: app
    reason: "Features must not depend on the app layer"
  - from: packages/core_*
    to: packages/feature_*
    reason: "Core packages must not depend on feature packages"

Step 4: Enforce Rules Locally

Run the dependency graph checker to validate your architecture:

bash
# Check all rules
dart run devtools dependency_graph --enforce

# Check a specific package
dart run devtools dependency_graph --enforce --package packages/feature_auth

Example violation output:

Dependency rule violations found:

  ✗ packages/core_network → packages/feature_auth
    Rule: Core packages must not depend on feature packages
    Fix: Extract shared types to packages/core_common or packages/shared_models

  ✗ packages/feature_home → packages/feature_auth
    Rule: Features should not depend on other features
    Fix: Extract shared logic to a core package

2 violations found. Exit code: 1

Step 5: Detect Circular Dependencies

Circular dependencies can cause build failures and indicate architectural issues. The graph command detects them automatically:

bash
dart run devtools dependency_graph --check-cycles

Example output when cycles are found:

Circular dependencies detected:

  ✗ packages/core_network → packages/core_storage → packages/core_network
    Fix: Break the cycle by extracting shared types into core_common

1 cycle found. Exit code: 1

Step 6: Integrate with CI

Add graph enforcement to your PR validation to prevent architectural drift:

yaml
- name: Check dependency rules
  run: dart run devtools dependency_graph --enforce

- name: Check for circular dependencies
  run: dart run devtools dependency_graph --check-cycles

- name: Generate dependency graph artifact
  if: always()
  run: |
    dart run devtools dependency_graph --format dot > deps.dot
    dot -Tpng deps.dot -o deps.png

- name: Upload graph
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: dependency-graph
    path: deps.png

Key Customization Points

CustomizationWhere to Change
Layer definitionsdependency_rules.yamllayers list
Banned dependenciesdependency_rules.yamlbanned list
Output format--format flag (dot, tree, json)
Check specific package--package flag
Cycle detection only--check-cycles flag

Next Steps

Built by Banua Coder