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 graphvizon macOS)
Step 1: Generate the Dependency Graph Command
bash
archipelago generate dependency_graphYou 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 treeExample tree output:
app
├── feature_auth
│ ├── core_network
│ │ └── core_common
│ └── core_storage
│ └── core_common
├── feature_home
│ └── core_network
│ └── core_common
└── app_debugger_impl
└── core_commonStep 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_authExample 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: 1Step 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-cyclesExample 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: 1Step 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.pngKey Customization Points
| Customization | Where to Change |
|---|---|
| Layer definitions | dependency_rules.yaml — layers list |
| Banned dependencies | dependency_rules.yaml — banned list |
| Output format | --format flag (dot, tree, json) |
| Check specific package | --package flag |
| Cycle detection only | --check-cycles flag |
Next Steps
- Set up affected detection to leverage the dependency graph in CI
- Configure test coverage to ensure quality across your graph