diagram-sync
v3.7.0
Published
Automatically export diagrams from PlantUML, Mermaid, Graphviz, Draw.io, D2, Excalidraw, and BPMN source files — keeps architecture documentation in sync with code across CI/CD pipelines, npm scripts, and local workflows.
Maintainers
Keywords
Readme
diagram-sync
Keep architecture diagrams synchronized with source code.
diagram-sync is a CLI tool that automatically generates images from diagram source files. Drop it into any repo and run npx diagram-sync — it finds every supported diagram file, renders it to an image, and mirrors the output under a diagrams/ folder. No config required.
npx diagram-sync
The Problem
Engineering teams update code but forget to re-export architecture diagrams. The result is stale documentation — READMEs, wikis, and onboarding docs that no longer reflect reality.
diagram-sync eliminates the manual export step entirely. You edit the diagram source file. It generates the image automatically — locally or in CI/CD.
Honest note: This tool removes export friction. It does not force developers to keep source diagrams accurate. That is a people problem, not a tooling problem.
Install
# one-off, no install required
npx diagram-sync
# or install globally
npm install -g diagram-sync
# or as a dev dependency
npm install --save-dev diagram-syncQuick Start
- Add a supported diagram source file anywhere in your repo
- Run
npx diagram-syncfrom the project root - Find the generated image in
diagrams/mirroring the source path
| Source | Generated | | --- | --- | | docs/└── providers/ ├── plantuml/ │ └── system.puml └── mermaid/ └── auth.mmd | diagrams/└── docs/ └── providers/ ├── plantuml/ │ └── system.svg └── mermaid/ └── auth.svg |
Once committed, the generated images are plain files in your repository — embed them in READMEs, wikis, internal docs, or link to them from anywhere on the internet via their raw GitHub URL.
How It Works
- Recursively scans your repo for diagram source files
- Skips
node_modules,.git,dist,build,diagrams - Derives the output path from the source file location — no input/output directories to configure
- Generates images using the installed diagram tool for each provider — defaults to SVG, configurable via
--formatflag or config file
Supported Providers
diagram-sync supports any diagram source that is committed to Git, maintained as a file, and can be converted to an image via a CLI — regardless of whether it was created by hand, a GUI tool, or AI.
| Provider | Extensions | Guide |
| --- | --- | --- |
| PlantUML | .puml, .plantuml | Setup & CI/CD |
| Mermaid | .mmd, .mermaid | Setup & CI/CD |
| Graphviz | .dot, .gv | Setup & CI/CD |
| Draw.io | .drawio, .dio | Setup & CI/CD |
| D2 | .d2 | Setup & CI/CD |
| Excalidraw | .excalidraw | Setup & CI/CD |
| BPMN | .bpmn | Setup & CI/CD |
Usage Options
1. One-off local generation
npx diagram-sync
2. npm script
"scripts": {
"diagrams": "npx diagram-sync"
}npm run diagrams
3. Regenerate specific files only
Pass explicit paths — skips discovery entirely. Used by CI to regenerate only the files changed in a push or PR.
npx diagram-sync --files docs/providers/d2/network.d2 docs/providers/plantuml/system.puml
4. Regenerate only locally changed files
Processes only files modified since the last commit (git diff HEAD + untracked). Useful locally to avoid regenerating every diagram in a large repo.
npx diagram-sync --changed
Exit codes and output names
diagram-sync exits with code 1 if any diagram fails to render, including a missing provider tool or a source file that doesn't exist, so CI jobs fail instead of passing silently.
Each source path/to/name.ext is written to diagrams/path/to/name.<format>, whatever title the diagram declares (for example @startuml My Title). If two sources in one folder share a name, such as architecture.puml and architecture.excalidraw, they write the same file; diagram-sync warns about it, and you should rename one of them.
5. Config file
Config is optional — no config file needed to get started. Add diagram-sync.config.json to your project root to control formats per provider or scope which providers run.
{
"format": "svg",
"jobs": [
{
"name": "architecture",
"type": "plantuml",
"format": "png",
"background": "#FFFFFF"
},
{
"name": "flows",
"type": "mermaid"
}
]
}npx diagram-sync --config diagram-sync.config.jsonOverride format at runtime without a config file:
npx diagram-sync --format svgFormat resolution order: --format flag → job format → global format → default svg.

Job Options
| Field | Type | Description |
| --- | --- | --- |
| name | string | Label for the job (used in logs) |
| type | string | Diagram provider (plantuml, mermaid, graphviz, drawio, d2, excalidraw, bpmn) |
| format | string | Output format for this job (e.g. png, svg, pdf) — overrides global format |
| background | string | Background color for PlantUML diagrams — defaults to #FFFFFF. Accepts hex codes or named colors (e.g. transparent, #F5F5F5) |
6. CI/CD
Generates a preview on every PR and commits images to main on merge.
Remove the install steps and path filters for providers you don't use — most teams only need 1–2.
name: Generate and Commit Diagrams
# Remove path entries for providers you don't use.
# The workflow only triggers when a matching source file changes.
on:
pull_request:
paths:
# PlantUML — remove if not using .puml / .plantuml files
- '**/*.puml'
- '**/*.plantuml'
# Mermaid — remove if not using .mmd / .mermaid files
- '**/*.mmd'
- '**/*.mermaid'
# Graphviz — remove if not using .dot / .gv files
- '**/*.dot'
- '**/*.gv'
# Draw.io — remove if not using .drawio / .dio files
- '**/*.drawio'
- '**/*.dio'
# D2 — remove if not using .d2 files
- '**/*.d2'
# Excalidraw — remove if not using .excalidraw files
- '**/*.excalidraw'
# BPMN — remove if not using .bpmn files
- '**/*.bpmn'
push:
branches: [main]
paths:
# PlantUML — remove if not using .puml / .plantuml files
- '**/*.puml'
- '**/*.plantuml'
# Mermaid — remove if not using .mmd / .mermaid files
- '**/*.mmd'
- '**/*.mermaid'
# Graphviz — remove if not using .dot / .gv files
- '**/*.dot'
- '**/*.gv'
# Draw.io — remove if not using .drawio / .dio files
- '**/*.drawio'
- '**/*.dio'
# D2 — remove if not using .d2 files
- '**/*.d2'
# Excalidraw — remove if not using .excalidraw files
- '**/*.excalidraw'
# BPMN — remove if not using .bpmn files
- '**/*.bpmn'
workflow_dispatch:
# Keep in sync with the providers you use. Paths are NUL-separated end to end
# (git diff -z | grep -z | xargs -0) so file names with spaces survive.
env:
DIAGRAM_PATTERN: '\.(puml|plantuml|mmd|mermaid|dot|gv|drawio|dio|d2|excalidraw|bpmn)$'
jobs:
preview:
name: Generate Preview
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v5
with:
# Full history required so git diff can resolve the base ref.
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v5
with:
node-version: '20'
# --- PlantUML — remove if not using .puml / .plantuml files ---
# Graphviz is needed for every PlantUML diagram type except sequence diagrams.
- name: Install PlantUML and Graphviz
run: |
sudo apt-get update -q
sudo apt-get install -y --no-install-recommends default-jre-headless plantuml graphviz
# --- Mermaid — remove if not using .mmd / .mermaid files ---
- name: Install Mermaid CLI
run: npm install -g @mermaid-js/mermaid-cli
# --- Graphviz — remove if not using .dot / .gv files (already installed above if using PlantUML) ---
- name: Install Graphviz
run: |
sudo apt-get update -q
sudo apt-get install -y graphviz
# --- Draw.io — remove if not using .drawio / .dio files ---
- name: Install Draw.io
run: |
DRAWIO_VERSION=$(curl -s https://api.github.com/repos/jgraph/drawio-desktop/releases/latest | jq -r '.tag_name | ltrimstr("v")')
wget -q "https://github.com/jgraph/drawio-desktop/releases/download/v${DRAWIO_VERSION}/drawio-amd64-${DRAWIO_VERSION}.deb" -O drawio.deb
sudo apt-get install -y ./drawio.deb xvfb
# --- D2 — remove if not using .d2 files ---
- name: Install D2
run: curl -fsSL https://d2lang.com/install.sh | sh
# --- Excalidraw — remove if not using .excalidraw files ---
- name: Install Excalidraw CLI
run: npm install -g @swiftlysingh/excalidraw-cli
# --- BPMN — remove if not using .bpmn files ---
- name: Install BPMN CLI
run: |
npm install -g bpmn-to-image
sed -i "s/headless: 'new'/headless: 'new', args: ['--no-sandbox', '--disable-setuid-sandbox']/" $(npm root -g)/bpmn-to-image/index.js
- name: Install diagram-sync
run: npm install -g diagram-sync
- name: Generate changed diagrams
env:
BASE_REF: ${{ github.base_ref }}
run: |
git diff -z --name-only --diff-filter=d "origin/${BASE_REF}...HEAD" \
| { grep -zE "$DIAGRAM_PATTERN" || echo "No diagram files changed." >&2; } \
| xargs -0 -r diagram-sync --files
# add --format png or --format pdf after --files to override the default svg output
# !cancelled() so previews of the diagrams that did render are still
# uploaded when another one fails
- name: Upload diagram previews
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: diagrams-preview
path: diagrams/
if-no-files-found: ignore
commit:
name: Generate and Commit
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
permissions:
contents: write
steps:
- uses: actions/checkout@v5
with:
# GITHUB_TOKEN with contents: write is enough when main is unprotected.
# If a branch ruleset blocks pushes from GITHUB_TOKEN, save a fine-grained PAT
# (Contents: read+write) as PAT_TOKEN; it is used automatically when present.
token: ${{ secrets.PAT_TOKEN || secrets.GITHUB_TOKEN }}
# Full history required so git diff can resolve the previous commit.
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v5
with:
node-version: '20'
# --- PlantUML — remove if not using .puml / .plantuml files ---
# Graphviz is needed for every PlantUML diagram type except sequence diagrams.
- name: Install PlantUML and Graphviz
run: |
sudo apt-get update -q
sudo apt-get install -y --no-install-recommends default-jre-headless plantuml graphviz
# --- Mermaid — remove if not using .mmd / .mermaid files ---
- name: Install Mermaid CLI
run: npm install -g @mermaid-js/mermaid-cli
# --- Graphviz — remove if not using .dot / .gv files (already installed above if using PlantUML) ---
- name: Install Graphviz
run: |
sudo apt-get update -q
sudo apt-get install -y graphviz
# --- Draw.io — remove if not using .drawio / .dio files ---
- name: Install Draw.io
run: |
DRAWIO_VERSION=$(curl -s https://api.github.com/repos/jgraph/drawio-desktop/releases/latest | jq -r '.tag_name | ltrimstr("v")')
wget -q "https://github.com/jgraph/drawio-desktop/releases/download/v${DRAWIO_VERSION}/drawio-amd64-${DRAWIO_VERSION}.deb" -O drawio.deb
sudo apt-get install -y ./drawio.deb xvfb
# --- D2 — remove if not using .d2 files ---
- name: Install D2
run: curl -fsSL https://d2lang.com/install.sh | sh
# --- Excalidraw — remove if not using .excalidraw files ---
- name: Install Excalidraw CLI
run: npm install -g @swiftlysingh/excalidraw-cli
# --- BPMN — remove if not using .bpmn files ---
- name: Install BPMN CLI
run: |
npm install -g bpmn-to-image
sed -i "s/headless: 'new'/headless: 'new', args: ['--no-sandbox', '--disable-setuid-sandbox']/" $(npm root -g)/bpmn-to-image/index.js
- name: Install diagram-sync
run: npm install -g diagram-sync
# continue-on-error so one broken diagram doesn't stop the others from being
# committed. The last step still fails the job if anything failed here.
- name: Generate diagrams
id: generate
continue-on-error: true
env:
EVENT_NAME: ${{ github.event_name }}
BEFORE_SHA: ${{ github.event.before }}
AFTER_SHA: ${{ github.sha }}
run: |
# Regenerate everything on manual runs, or when there is no previous
# commit to diff against (first push / new branch).
if [ "$EVENT_NAME" = "workflow_dispatch" ] || [ -z "$BEFORE_SHA" ] || [ "$BEFORE_SHA" = "0000000000000000000000000000000000000000" ]; then
diagram-sync
else
git diff -z --name-only --diff-filter=d "$BEFORE_SHA" "$AFTER_SHA" \
| { grep -zE "$DIAGRAM_PATTERN" || echo "No diagram files changed." >&2; } \
| xargs -0 -r diagram-sync --files
fi
- name: Commit generated diagrams
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# diagrams/ may not exist yet if nothing has been generated
git add diagrams/ 2>/dev/null || true
if git diff --staged --quiet; then
echo "No diagram changes to commit."
else
git commit -m "chore: auto-export diagrams [skip ci]"
# main may have moved while diagrams were rendering
git pull --rebase origin main
git push
fi
# outcome, not conclusion: continue-on-error turns the conclusion into success
- name: Fail if any diagram failed to render
if: steps.generate.outcome == 'failure'
run: |
echo "::error::Some diagrams failed to render. The ones that succeeded were committed; see the Generate diagrams step for details."
exit 1No secrets setup required — GITHUB_TOKEN with contents: write works out of the box for unprotected branches. If your main branch is protected and blocks pushes from GITHUB_TOKEN, save a fine-grained PAT (Contents: read and write) as the PAT_TOKEN secret; the workflow picks it up automatically. See the Provider Guides for the ready-to-use workflow file.
Requirements
- Node.js 20+
- Each provider requires its own CLI tool — install only what you need:
- PlantUML: Java 11+, PlantUML, and Graphviz (needed for every diagram type except sequence diagrams) — see PlantUML guide
- Mermaid: see Mermaid guide
- Graphviz: see Graphviz guide
- Draw.io: requires
draw.ioandxvfb(Linux only) —diagram-syncauto-usesxvfb-runfor headless rendering when no display is available — see Draw.io guide - D2: see D2 guide
- Excalidraw: requires
@swiftlysingh/excalidraw-cli— SVG and PNG, no browser required — see Excalidraw guide - BPMN: requires
bpmn-to-image— SVG, PNG and PDF — on CI, patch with--no-sandboxafter install (see BPMN guide)
Providers are detected at runtime and missing ones are skipped with a warning.
Common Use Cases
- How to automate PlantUML diagram generation in CI/CD
- How to automate Mermaid diagram generation in CI/CD
- How to automate Graphviz diagram generation in CI/CD
- How to convert Draw.io files to images automatically in CI/CD
- How to automate D2 diagram generation in CI/CD
- How to export Excalidraw files to SVG or PNG automatically in CI/CD
- How to automate BPMN process diagram generation in CI/CD
- How to keep README architecture diagrams up to date automatically
- How to sync architecture diagrams from source files
- How to generate architecture diagrams on GitHub Actions
- How to treat architecture diagrams as code
- Documentation-as-code workflow for PlantUML, Mermaid, D2, and more
Links
- npm: https://www.npmjs.com/package/diagram-sync
- GitHub: https://github.com/Buffden/diagram-sync
- Provider Guides: https://github.com/Buffden/diagram-sync/tree/main/docs/providers
License
MIT — Buffden
