Skip to content

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:

  1. Developer changes code in src/services/user-api/
  2. I remember to update the draw.io diagram (sometimes)
  3. Export to PNG
  4. Upload to Confluence
  5. 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:

  1. Extract code structure - Use static analysis tools or AI-powered analysis
  2. Generate diagrams - Convert extracted data to visual format
  3. Commit back to repo - Automatically push updated diagrams

Here’s the complete workflow I set up:

.github/workflows/diagrams.yml
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 push

I can explain the key parts:

  • Trigger: Runs on push to main when TypeScript/JavaScript files change
  • Permissions: Needs contents: write to 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:

scripts/generate-diagrams.js
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 execution
const 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:

Terminal window
$ node scripts/generate-diagrams.js --input deps.json --output docs/diagrams
Diagrams generated successfully

It creates docs/diagrams/architecture.mmd with content like:

docs/diagrams/architecture.mmd
graph TD
user-api --> auth-service
user-api --> database
auth-service --> redis
auth-service --> database

Advanced 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:

.github/workflows/diagrams.yml
- 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:

.github/workflows/diagrams.yml
- 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:

scripts/generate-multiple-formats.js
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:

  • .mmd files for markdown rendering in GitHub/GitLab
  • .png files for presentations and documentation sites
  • .svg files for responsive web rendering

Full-System Architecture Generation

For microservices architectures, I set up a separate workflow that generates cross-service dependency diagrams weekly:

.github/workflows/full-diagrams.yml
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.js

This 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:

MCP-based diagram generation
# 1. Start MCP server for code analysis
npx @modelcontextprotocol/server-filesystem
# 2. In CI/CD pipeline, use Claude Code CLI
claude-code \
--mcp-server filesystem \
--prompt "Analyze src/ directory and generate architecture diagram in Mermaid format" \
--output docs/diagrams/architecture.mmd
# 3. Commit generated diagram
git add docs/diagrams/architecture.mmd

The 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:

ToolLanguageOutput FormatCI/CD ReadyNotes
dependency-cruiserJS/TSJSON, DOT, MermaidBest for Node.js projects
pydepsPythonGraphviz DOTSimple, fast for Python codebases
golang dependency analysisGoText, JSONBuilt into Go toolchain
PlantUMLAnyPNG, SVGRequires Java runtime
Mermaid CLIAnySVG, PNGNo dependencies, markdown-native
Claude Code + MCPAnyMultipleBest 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:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments