How to Integrate Auto-Generated Architecture Diagrams into CI/CD Pipeline
The Problem
I manage a fast-moving microservices codebase where architecture changes happen weekly. Every time someone modifies service dependencies, I face the same problem: the architecture diagrams in our documentation become outdated.
Here’s what I tried at first:
- Developer changes code in
src/services/user-api/ - I remember to update the draw.io diagram (sometimes)
- Export to PNG
- Upload to Confluence
- Repeat every time code changes
This manual workflow doesn’t scale. After two months, our diagrams showed dependencies that didn’t exist anymore. New engineers joined and got confused by stale documentation. Architecture reviews turned into arguments because no one trusted the diagrams.
I needed a way to keep diagrams in sync with code automatically, ideally integrated into our CI/CD pipeline so updates happen without human intervention.
Why CI/CD Integration Matters
When I looked at how other teams solved this, I found a common pattern: treat diagrams as derived artifacts from source code, not manual documentation.
Here’s why CI/CD integration works better than manual updates:
- Single source of truth: Your code is the diagram source
- Zero manual maintenance: Diagrams update automatically on code changes
- Version controlled: Track architecture evolution over time through git history
- Reviewable: Diagram changes appear in pull requests alongside code changes
- Scalable: Works for microservices, monorepos, and polyglot codebases
The core insight from the DevOps community: diagrams should be generated on every code change, not on demand. When someone pushes code, the pipeline should extract dependencies, generate diagrams, and commit them back to the repository.
The Solution: Three-Phase Pipeline Integration
I implemented diagram generation as a CI/CD pipeline step with three phases:
- Extract code structure - Use static analysis tools or AI-powered analysis
- Generate diagrams - Convert extracted data to visual format
- Commit back to repo - Automatically push updated diagrams
Here’s the complete workflow I set up:
name: Update Architecture Diagrams
on: push: branches: [main] paths: - 'src/**/*.ts' - 'src/**/*.js'
permissions: contents: write
jobs: generate-diagrams: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18'
- name: Install dependencies run: npm install
- name: Analyze code dependencies run: | npx dependency-cruiser src --output-type json > deps.json
- name: Generate Mermaid diagrams run: | node scripts/generate-diagrams.js --input deps.json --output docs/diagrams
- name: Commit and push run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git add docs/diagrams/ git diff --staged --quiet || git commit -m "chore: auto-update architecture diagrams" git pushI can explain the key parts:
- Trigger: Runs on push to
mainwhen TypeScript/JavaScript files change - Permissions: Needs
contents: writeto commit diagrams back - dependency-cruiser: Extracts module dependencies as JSON
- Custom script: Converts JSON to Mermaid diagram format
- Conditional commit: Only commits if diagrams actually changed (
git diff --staged --quiet)
The workflow generates diagrams on every code change and commits them back to the repository. No manual intervention required.
Diagram Generation Script
Here’s the script I wrote to convert dependency JSON to Mermaid format:
const fs = require('fs');
function generateMermaidGraph(deps) { let graph = 'graph TD\n';
deps.modules.forEach(mod => { const name = mod.source.replace(/.*src\//, '').replace('.ts', ''); mod.dependencies.forEach(dep => { const depName = dep.resolved.replace(/.*src\//, '').replace('.ts', ''); graph += ` ${name} --> ${depName}\n`; }); });
return graph;}
// Main executionconst deps = JSON.parse(fs.readFileSync('deps.json', 'utf8'));const mermaidGraph = generateMermaidGraph(deps);
fs.mkdirSync('docs/diagrams', { recursive: true });fs.writeFileSync('docs/diagrams/architecture.mmd', mermaidGraph);console.log('✅ Diagrams generated successfully');The script reads the dependency JSON from dependency-cruiser, iterates through modules and their dependencies, and generates Mermaid syntax. I use Mermaid because it renders natively in GitHub and GitLab markdown, so the diagrams are viewable directly in pull requests.
When I run this locally:
$ node scripts/generate-diagrams.js --input deps.json --output docs/diagrams✅ Diagrams generated successfullyIt creates docs/diagrams/architecture.mmd with content like:
graph TD user-api --> auth-service user-api --> database auth-service --> redis auth-service --> databaseAdvanced Pipeline Features
Once I had basic diagram generation working, I added more sophisticated features to make the workflow more useful.
Detect Actual Changes
I noticed early on that the pipeline was committing even when diagrams didn’t change. I added a check to only commit when there are actual differences:
- name: Check for diagram changes id: detect_changes run: | if git diff --quiet docs/diagrams/; then echo "changed=false" >> $GITHUB_OUTPUT else echo "changed=true" >> $GITHUB_OUTPUT fi
- name: Commit diagrams if: steps.detect_changes.outputs.changed == 'true' run: | git add docs/diagrams/ git commit -m "chore: update architecture diagrams"PR Comments with Diagram Preview
I wanted reviewers to see architecture changes directly in pull requests. I added a step that comments on PRs with the diagram diff:
- name: Comment PR with diagram changes if: github.event_name == 'pull_request' uses: actions/github-script@v6 with: script: | const { execSync } = require('child_process'); const diff = execSync('git diff docs/diagrams/architecture.mmd').toString(); github.rest.issues.createComment({ issue_number: context.issue.number, body: `## 🏗️ Architecture Changes\n\n\`\`\`diff\n${diff}\n\`\`\`` });Now when someone opens a PR that changes service dependencies, they see a comment showing exactly what changed in the architecture diagram.
Multi-Format Output
Different teams in my organization need different diagram formats. I extended the script to generate multiple outputs:
const { execSync } = require('child_process');
function generateMultipleFormats(deps) { // Mermaid for GitLab/GitHub markdown rendering const mermaid = generateMermaidGraph(deps); fs.writeFileSync('docs/diagrams/architecture.mmd', mermaid);
// Graphviz DOT for PNG/SVG rendering const dot = generateGraphvizDOT(deps); fs.writeFileSync('docs/diagrams/architecture.dot', dot);
// Generate PNG using Graphviz execSync('dot -Tpng docs/diagrams/architecture.dot -o docs/diagrams/architecture.png');
// Generate SVG for web rendering execSync('dot -Tsvg docs/diagrams/architecture.dot -o docs/diagrams/architecture.svg');}This gives us:
.mmdfiles for markdown rendering in GitHub/GitLab.pngfiles for presentations and documentation sites.svgfiles for responsive web rendering
Full-System Architecture Generation
For microservices architectures, I set up a separate workflow that generates cross-service dependency diagrams weekly:
name: Generate Full System Architecture
on: schedule: - cron: '0 0 * * 0' # Weekly on Sunday workflow_dispatch:
jobs: full-system: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Generate microservices architecture run: | # Analyze all services for service in services/*/; do npm run analyze:service -- $service >> full-deps.json done
# Generate cross-service dependency graph node scripts/generate-cross-service-diagram.jsThis runs weekly to create a complete system architecture view showing how all services interact. The manual trigger (workflow_dispatch) lets me regenerate on demand after major refactors.
Alternative: AI-Powered Analysis with MCP
For polyglot codebases where static analysis tools don’t exist for every language, I tried using Model Context Protocol (MCP) servers with Claude Code:
# 1. Start MCP server for code analysisnpx @modelcontextprotocol/server-filesystem
# 2. In CI/CD pipeline, use Claude Code CLIclaude-code \ --mcp-server filesystem \ --prompt "Analyze src/ directory and generate architecture diagram in Mermaid format" \ --output docs/diagrams/architecture.mmd
# 3. Commit generated diagramgit add docs/diagrams/architecture.mmdThe MCP server gives Claude Code access to filesystem operations, enabling AI-powered code analysis that understands patterns across languages. This works well when you need semantic understanding (like identifying service boundaries) rather than just dependency extraction.
Tool Selection Guide
I tested several diagram generation tools. Here’s what I found:
| Tool | Language | Output Format | CI/CD Ready | Notes |
|---|---|---|---|---|
| dependency-cruiser | JS/TS | JSON, DOT, Mermaid | ✅ | Best for Node.js projects |
| pydeps | Python | Graphviz DOT | ✅ | Simple, fast for Python codebases |
| golang dependency analysis | Go | Text, JSON | ✅ | Built into Go toolchain |
| PlantUML | Any | PNG, SVG | ✅ | Requires Java runtime |
| Mermaid CLI | Any | SVG, PNG | ✅ | No dependencies, markdown-native |
| Claude Code + MCP | Any | Multiple | ✅ | Best for polyglot/semantic analysis |
For my use case (TypeScript microservices), dependency-cruiser + Mermaid works best. Python teams should use pydeps. Go teams can use built-in dependency analysis.
Common Pitfalls I Encountered
Generating only on demand: Initially I generated diagrams manually with a script command. This broke because I forgot to run it. I moved generation to CI/CD to force automation.
Not committing diagrams: I tried generating diagrams on-the-fly in the documentation site build. This broke reproducibility because the docs showed different diagrams each time without git history. Now I commit diagrams to the repository.
Wrong diagram type: I started with sequence diagrams showing call flows. But for CI/CD automation, component diagrams showing module dependencies are more useful. Sequence diagrams require understanding runtime behavior, which is harder to extract statically.
Ignoring build failures: When diagram generation failed, the pipeline continued. This produced empty diagrams that committed to the repo. I made diagram generation failures fail the build.
Missing PR previews: I didn’t show diagram changes in PRs initially, so reviewers couldn’t see architecture impact. Adding PR comments solved this.
The Results
After implementing CI/CD diagram generation, here’s what changed:
- Onboarding time dropped: New engineers reference up-to-date diagrams that match the code
- Architecture reviews improved: Reviewers see dependency changes directly in PRs
- Documentation trust restored: Teams know diagrams are always current
- Zero maintenance overhead: No manual diagram updates required
The diagrams now update automatically on every code change. When someone adds a dependency between services, the next pipeline run detects the change, regenerates the diagram, and commits it back to the repository.
Summary
In this post, I showed how to integrate auto-generated architecture diagrams into CI/CD pipeline by adding diagram generation as a pipeline step. The key point is treating diagrams as derived artifacts from source code, not manual documentation.
I demonstrated:
- Extracting code dependencies with static analysis tools
- Generating Mermaid diagrams from dependency data
- Committing diagrams back to the repository automatically
- Adding PR previews for architecture changes
- Supporting multiple diagram formats for different use cases
The solution eliminates manual diagram maintenance by generating diagrams on every code change. Your architecture documentation stays perpetually in sync with zero human effort.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 dependency-cruiser
- 👨💻 Mermaid.js
- 👨💻 Model Context Protocol
- 👨💻 GitHub Actions Documentation
- 👨💻 pydeps - Python dependency visualization
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments