Monorepo Toolkit
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)
- Graphviz installed if you want to render DOT output to an image (
brew install graphvizon macOS)
The graph command is part of the free monorepo_toolkit, so every generated project already has it. There is nothing to generate separately.
Step 1: Visualize Your Dependencies
Generate a visual graph of all package relationships:
# Text overview to the terminal (default)
dart run monorepo_toolkit graph visualize
# DOT format, then render to PNG
dart run monorepo_toolkit graph visualize --format dot --output deps.dot
dot -Tpng deps.dot -o deps.png
# Mermaid for Markdown, or JSON for tooling
dart run monorepo_toolkit graph visualize --format mermaid --output deps.md
dart run monorepo_toolkit graph visualize --format json --output deps.jsonGet headline numbers (package count, edges, most depended-on packages) with:
dart run monorepo_toolkit graph statsStep 2: Understand the Layer Rules
graph validate enforces the architecture rules. They are built into the toolkit, not read from a config file. Dependencies must flow downward:
apps/ -> features/ -> infrastructure/ -> packages/ -> shared/ -> utilities/| Rule | Description |
|---|---|
api-restricted-deps | *_api packages depend only on shared/, utilities/ and other *_api packages |
no-impl-cross-dep | *_impl packages cannot depend on *_impl packages of other features |
shared-no-upward-dep | shared/ cannot depend on features/, infrastructure/, packages/ or apps/ |
utility-no-upward-dep | utilities/ cannot depend on features/, infrastructure/, packages/ or apps/ |
no-upward-dep | packages/ cannot depend on feature impl or app packages |
no-devtools-dep | App packages cannot depend on devtools packages |
Packages are categorized by their directory (apps/, features/, infrastructure/, shared/, ...) and _api/_impl suffix. See Dependency Graph for the full table.
Step 3: Enforce Rules Locally
dart run monorepo_toolkit graph validate
# Include the package categories and passing checks
dart run monorepo_toolkit graph validate --verboseWhen a rule is broken, the command lists each violation and exits with code 1. Fix it by moving the shared type down into a package the offender is allowed to depend on (usually an _api package or shared/).
Step 4: Detect Circular Dependencies
Circular dependencies can cause build failures and indicate architectural issues:
dart run monorepo_toolkit graph cyclesIt prints each detected cycle and exits with code 1. Pass --no-fail to report cycles without failing the command.
Step 5: Integrate with CI
Add graph enforcement to your PR validation to prevent architectural drift:
- name: Validate dependency rules
run: dart run monorepo_toolkit graph validate
- name: Check for circular dependencies
run: dart run monorepo_toolkit graph cycles
- name: Generate dependency graph artifact
if: always()
run: |
dart run monorepo_toolkit graph visualize --format dot --output 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 |
|---|---|
| Output format | graph visualize --format (text, dot, mermaid, json) |
| Write to a file | graph visualize --output |
| Detailed validation output | graph validate --verbose |
| Cycles as warning only | graph cycles --no-fail |
| The rules themselves | devtools/scripts/dependency_graph/lib/src/commands/validate_command.dart (generated into your project, so you own it) |
Next Steps
- Set up affected detection to leverage the dependency graph in CI
- Configure test coverage to ensure quality across your graph