You wrote your documentation in Markdown.
You added Mermaid diagrams because they’re version-controlled, diff-friendly, and faster to edit than dragging boxes around in a GUI.
Then someone asked for a Word document, and everything fell apart.
The problem
Pandoc handles the Markdown-to-.docx conversion well enough. Headers, tables, code blocks, links: all fine. But Mermaid diagrams? Pandoc sees a fenced code block tagged mermaid and treats it as plain text. Your flowchart shows up as raw syntax in the Word doc, which is arguably worse than having no diagram at all.
If you keep documentation in Markdown and periodically need to hand Word files to people who don’t read .md files, you’ve probably been here before. You end up either maintaining two versions of every diagram (one in Mermaid, one as a manually exported PNG) or screenshotting from a browser and pasting into the doc. Both get out of sync fast.
The fix
There’s a pandoc filter called mermaid-filter that does exactly what you’d expect: it intercepts Mermaid code blocks during conversion, renders them into images, and hands the images back to pandoc for embedding in the output. Your Markdown stays the single source of truth.
Install the tools
You need pandoc and the mermaid filter. If you’re on macOS:
brew install pandoc
npm install -g mermaid-filter
On Linux, swap brew install pandoc for your package manager’s equivalent (apt install pandoc, dnf install pandoc, etc.). The npm package works the same everywhere.
Convert a single file
pandoc input.md --filter mermaid-filter -o output.docx
One command. Pandoc reads the Markdown, the filter renders every mermaid block to an image, and the result lands in the Word document. Everything else passes through untouched.
Convert every Markdown file in a directory
for f in *.md; do pandoc "$f" --filter mermaid-filter -o "${f%.md}.docx"; done
Each .md file gets a corresponding .docx with the same base name. The loop handles any number of files and works in both bash and zsh.
What it looks like in practice
Say your Markdown contains this:
```mermaid
graph LR
A[User] --> B[API Gateway]
B --> C[Lambda]
C --> D[(DynamoDB)]
```
Without the filter, pandoc dumps that text verbatim into Word. With mermaid-filter, the .docx contains a rendered diagram showing the four nodes and their connections. The text block disappears entirely and an image takes its place.
Gotchas
A few things I ran into that are worth mentioning. The filter shells out to Chromium under the hood (via puppeteer), so the first run downloads a Chromium binary if one isn’t cached. This can be slow on a fresh machine and will fail in environments with no network access. If you’re running this in CI, make sure the Chromium dependency is pre-installed or cached.
The filter defaults to PNG output. For most Word documents this is fine, but if you need vector graphics you can set the output format to SVG by passing environment variables (MERMAID_FILTER_FORMAT=svg). SVG embedding in .docx is hit-or-miss depending on which version of Word opens the file, so I’d stick with PNG unless you have a specific reason not to.
Complex diagrams with many nodes can take a noticeable amount of time to render. If you have dozens of Mermaid blocks in a single document, the conversion won’t be instant. Not a problem for most documentation, but worth knowing if you’re generating large reference manuals.
Wrapping up
Two install commands and one conversion command. That’s the whole thing. Your Markdown stays as-is, the diagrams show up as real images in Word, and you stop maintaining parallel copies of anything. Next time someone asks for “the docs in Word format,” you run a one-liner and get back to actual work.