Why mermaid diagrams don't render in PDF (and how to fix it)
If your Markdown exports to PDF with the mermaid diagram showing up as raw code (the graph TD; A-->B text instead of an actual diagram), the reason is fundamental: mermaid is a JavaScript library that draws diagrams by running code in a browser. Any converter that does not execute JavaScript, which includes most static Markdown-to-PDF tools, pandoc without a special filter, and nbconvert, has no way to turn the mermaid code into a picture, so it leaves the code block as-is. To get a rendered diagram you need a converter that actually runs mermaid.js (a headless-browser or browser-based tool), or you pre-render the diagram to an image first. PDFMoka's markdown to PDF converter runs mermaid in the browser so diagrams render to the PDF; below is why this happens and every way to fix it.
The root cause: mermaid needs JavaScript to exist as a picture
A mermaid diagram in Markdown is just a fenced code block tagged mermaid:
```mermaid
graph TD;
A-->B;
A-->C;
```
That text is not an image. It only becomes a diagram when mermaid.js parses it and draws SVG, and that requires a JavaScript runtime. This is why the same diagram renders on GitHub or in a live preview but comes out as plain code in an export: GitHub and the preview run JavaScript; the exporter often does not. As the mermaid community puts it, treat mermaid as a renderer feature, not as portable Markdown, whether it renders depends entirely on the destination running mermaid.
So the failure splits into two questions: does your converter run JavaScript at all, and if so, is mermaid actually being invoked?
Fix 1: use a converter that runs mermaid.js
Tools that drive a headless browser (or run in the browser) can execute mermaid and capture the resulting diagram.
-
Browser-based converter: PDFMoka's markdown to PDF tool renders mermaid in your browser and includes the drawn diagram in the PDF, with no upload and no local setup. (Implementation note: mermaid is loaded on demand only when a document actually contains a mermaid block, so documents without diagrams stay lightweight.)
verify against your build: confirm the exact behavior of your own converter on a document with several mermaid blocks before publishing, specifically, whether every diagram type you care about (flowchart, sequence, gantt, state) renders, and what the tool does when a diagram fails to parse (see Fix 3). Describe the real, observed behavior here rather than assuming.
-
VS Code "Markdown PDF" and similar extensions: these use headless Chromium and can render mermaid, but a well-known gotcha is that mermaid stays as raw code unless the extension's Chromium path (
executablePath) is configured. If your extension exports code instead of diagrams, check that setting. -
Pandoc: does not render mermaid on its own. You need a filter such as
mermaid-filter(which itself calls mermaid-cli), plus its dependencies. Without the filter, pandoc passes the code block through unrendered.
Fix 2: pre-render the diagram to an image (works everywhere)
If you must use a converter that cannot run mermaid (a pure static/LaTeX pipeline), convert the diagram to a static image before the Markdown export, then reference that image instead of the code block. The mermaid CLI does this:
npm install -g @mermaid-js/mermaid-cli
mmdc -i diagram.mmd -o diagram.svg # or .png
Then in your Markdown, replace the ```mermaid fenced block with . Now any converter, even one that ignores JavaScript, embeds the image like any other picture. This is the most portable fix: it removes the JavaScript dependency from export time entirely.
verify against current docs: the mermaid-cli package name and
mmdcflags are current, but confirm before relying on them; mermaid-cli itself uses a headless browser under the hood, so it has its own Chromium requirement.
Fix 3: when the diagram is valid but still fails
Sometimes the converter does run mermaid but the diagram still breaks (a bomb icon, a blank space, or a getBoundingClientRect error). Common causes:
- A mermaid syntax error. One malformed line fails the whole diagram. Test the diagram in the mermaid live editor to isolate syntax problems from converter problems.
- A mermaid version mismatch. Some export tools pin an old mermaid version that chokes on newer syntax (or vice versa). If a diagram works in one tool and not another, version skew is a prime suspect.
- Timing/layout issues in headless rendering, the diagram is captured before mermaid finishes drawing. This is a tool bug, not your diagram; a mature converter waits for render completion.
A good converter should tell you when a diagram could not be rendered rather than silently dropping it. If you rely on diagrams in important documents, prefer a tool that surfaces a clear warning on failure.
Which fix?
- Want diagrams to just render, no pre-processing: use a converter that runs mermaid.js, like PDFMoka's markdown to PDF.
- Stuck with a static/LaTeX pipeline: Fix 2, pre-render to SVG/PNG with mermaid-cli and embed the image.
- Diagram renders elsewhere but fails on export: check syntax in the live editor and suspect a mermaid version mismatch.
For the related math-rendering version of this same "needs special handling" problem, see rendering LaTeX math in Markdown PDF exports.
References
- GitHub Blog, "Include diagrams in your Markdown files with Mermaid" (mermaid runs in the browser via JS/iframe): https://github.blog/developer-skills/github/include-diagrams-markdown-files-mermaid/
- Mermaid documentation: https://mermaid.js.org/
- mermaid-cli (
mmdc) repository: https://github.com/mermaid-js/mermaid-cli