Does Doxygen support Mermaid diagrams? Yes — since 1.17.0, and here is how to enable it
Doxygen shipped native Mermaid support in 1.17.0 (30 April 2026): the @mermaid, @endmermaid and @mermaidfile commands plus five config options. Here is how to turn it on, the CLI vs client-side render modes, the CDN gotcha, and why AWS icons still need an exported image.
Yes — since Doxygen 1.17.0, released 30 April 2026. Native Mermaid arrived with three commands (@mermaid, @endmermaid, @mermaidfile) plus five configuration options. Diagrams render either client-side from a CDN or server-side through mermaid-cli. Cloud architecture diagrams using aws: slugs still need a pre-rendered image, because neither mode registers icon packs.
For years the answer to "can I use Mermaid in Doxygen?" was no. Doxygen's built-in diagramming was Graphviz and PlantUML, and everyone else made do with a custom HTML header, an ALIASES hack, or a pre-rendered PNG.
That changed on 30 April 2026. Doxygen 1.17.0 shipped native Mermaid support — three new commands and five new configuration options — and most of the advice you will find online, including the guidance we published here in June, still describes the old world.
This post is the current answer: which version you need, how to turn it on, the two render modes and why the choice matters more than it looks, the CDN issue that bites offline documentation builds, and the one thing native support still does not do — draw cloud provider icons. For the same question across other platforms, see the platform rendering guide or the Bitbucket deep dive.
Upgrade to Doxygen 1.17.0 or later, then use @mermaid … @endmermaid for inline diagrams and @mermaidfile for external .mmd files. Set MERMAID_RENDER_MODE = CLI unless you specifically want browser-side rendering. Cloud architecture diagrams are the exception: no render mode registers icon packs, so export those from LatixEngine and include them with \image.
Does Doxygen support Mermaid diagrams?
Yes, natively, from version 1.17.0 onward.
The release added three commands and five configuration options. Here is the whole surface area in one place:
| Item | Type | What it is for |
|---|---|---|
| @mermaid / @endmermaid | Block command | Wraps an inline Mermaid diagram written directly in a comment |
| @mermaidfile | Command | Includes a diagram from an external .mmd file |
| MERMAID_RENDER_MODE | Config | Chooses server-side (CLI) or client-side rendering |
| MERMAID_PATH | Config | Where to find the mermaid-cli executable, for CLI mode |
| MERMAID_JS_URL | Config | Which mermaid.js build the browser loads, for client-side mode |
| MERMAID_CONFIG_FILE | Config | A Mermaid configuration file applied to your diagrams |
| MERMAIDFILE_DIRS | Config | Where to search for the .mmd files that @mermaidfile references |
If you have used Doxygen's PlantUML support, the shape will be familiar: MERMAIDFILE_DIRS mirrors PLANTUMLFILE_DIRS and DOTFILE_DIRS, and MERMAID_PATH mirrors PLANTUML_JAR_PATH. This was deliberately modelled on the existing diagram integrations rather than invented from scratch.
If you go looking for the feature request, the one you will find is closed and labelled wontfix — which reads as though this never shipped. It did. The changelog for 1.17.0 is the authoritative source, and the five MERMAID_* options are all recorded as introduced in that version.
Which Doxygen version do you need?
1.17.0 or later. Check before you debug anything else:
doxygen --versionThe behaviour splits cleanly at that boundary, and knowing which side you are on saves a lot of wasted time:
| Your version | Mermaid commands | What to do |
|---|---|---|
| 1.17.0 or newer | @mermaid, @endmermaid, @mermaidfile | Configure it, as below |
| 1.16.x or older | None — the commands are unrecognised | Upgrade, or use a community workaround |
The failure mode on an older version is quiet rather than loud: Doxygen does not recognise @mermaid, so it treats the block as ordinary comment text and your diagram source appears verbatim in the generated documentation. If you are seeing raw Mermaid code in your HTML output, check your version first.
How do you enable Mermaid in Doxygen?
Minimal working configuration, server-side rendering:
# Doxyfile
MERMAID_RENDER_MODE = CLI
MERMAID_PATH = /usr/local/bin
MERMAIDFILE_DIRS = docs/diagramsMERMAID_PATH points at the directory containing the mermaid-cli executable, which you install separately:
npm install -g @mermaid-js/mermaid-cliFor client-side rendering instead, leave MERMAID_RENDER_MODE at its default and Doxygen injects a script tag built from MERMAID_JS_URL. You need no local Mermaid install at all in that mode — the reader's browser does the work.
How do you write a Mermaid diagram in a Doxygen comment?
Wrap it in the block command, inside any documentation comment:
/**
* @brief Parses an incoming frame.
*
* The parser is a small state machine:
*
* @mermaid
* stateDiagram-v2
* [*] --> Idle
* Idle --> Header: byte received
* Header --> Payload: length valid
* Header --> Error: length invalid
* Payload --> Checksum: payload complete
* Checksum --> Idle: checksum ok
* Checksum --> Error: checksum bad
* Error --> Idle: reset()
* @endmermaid
*/
int parse_frame(const uint8_t *buf, size_t len);State machines, sequence diagrams, and flowcharts are where this earns its keep, because the diagram sits next to the function it describes and changes in the same commit.
If you prefer the backslash form of Doxygen commands, \mermaid and \endmermaid work identically — the @ and \ prefixes are interchangeable throughout Doxygen.
How do you include an external .mmd file?
For anything bigger than a few lines, keep the diagram in its own file and reference it:
/**
* @brief Overall pipeline.
*
* @mermaidfile{ingest-pipeline.mmd}
*/Then tell Doxygen where to look:
MERMAIDFILE_DIRS = docs/diagramsThis is the better default for anything you will maintain. A .mmd file is a first-class text file: it diffs cleanly in review, your editor can syntax-highlight it, and you can render it in any other Mermaid tool without first extracting it from a C comment. Diagrams buried in comment blocks tend to rot because nobody wants to edit a diagram through a *-prefixed margin.
What is the difference between the CLI and client-side render modes?
This is the configuration choice that matters most, and the trade-offs run in opposite directions.
| MERMAID_RENDER_MODE = CLI | Client-side (default) | |
|---|---|---|
| Renders | At documentation build time | In the reader's browser, on page load |
| Needs | mermaid-cli installed on the build machine | Nothing locally |
| Loads mermaid.js | No | Yes, from MERMAID_JS_URL |
| Works offline | Yes | Only if you self-host the script |
| Build speed | Slower | Faster |
| Fails when | Build machine lacks mermaid-cli | Reader has no network, or CDN is blocked |
| Diagram in output | Baked-in image | Rendered live from source |
The rule of thumb: if the documentation will ever be read offline, use CLI. Docs shipped inside a release tarball, published on an internal network, or opened from a local file:// path all fall into that category, and client-side mode degrades badly there — the diagram simply never appears.
Client-side mode makes sense for docs served over the public web where you want fast builds, and where a reader always has the CDN available.
Why does Doxygen load mermaid.js when you have no diagrams?
Because of a genuine wrinkle in 1.17.0 that is worth knowing before you upgrade: Doxygen includes the Mermaid JavaScript resources in the HTML output even for projects that contain no Mermaid diagrams at all. Since the default MERMAID_JS_URL points at a CDN, browsers reading the docs offline try to fetch a script they will never get, and the result is noticeable UI lag on every page.
The fix is the same switch as above:
MERMAID_RENDER_MODE = CLIIn CLI mode no Mermaid JavaScript is emitted, so the problem disappears whether or not you actually use Mermaid. Dimitri van Heesch pointed to this as the workaround when the behaviour was reported, and the issue is now closed — but the interaction is not obvious from the configuration documentation, so it catches people out. If you upgraded to 1.17.0 and your unrelated C++ docs suddenly feel sluggish, this is why.
Does Doxygen's Mermaid support render AWS architecture diagrams?
No — and this is the one limitation native support does not remove.
Mermaid's architecture-beta diagram type ships five built-in shapes (cloud, database, disk, internet, server). Cloud provider artwork comes from icon packs that the host application must register through Mermaid's registerIconPacks() API at initialisation. That is a JavaScript call, not a setting.
Doxygen gives you no hook for it in either mode:
CLImode shells out to mermaid-cli, which has no cloud icon packs bundled.- Client-side mode injects a plain script tag.
MERMAID_CONFIG_FILEtakes a Mermaid configuration file, which has fields for themes and diagram defaults — and no field for registering icon packs, because registration is code rather than configuration.
So this renders as three empty labelled boxes:
architecture-beta
group vpc(aws:virtual-private-cloud-vpc)[Production VPC]
service app(aws:arch-amazon-ec2)[App Server] in vpc
service db(aws:arch-amazon-rds)[Database] in vpc
app:R --> L:dbThe syntax is valid and every slug is real. Doxygen just has nothing to resolve them against. This is the same wall GitHub, Bitbucket, Notion, and Confluence all hit, for the same reason — see why cloud icons fail everywhere for the full explanation.
Is there any way to get cloud icons rendering in Doxygen?
There is one theoretical route, and it is worth knowing about mainly so you can decide against it.
In client-side mode you control MERMAID_JS_URL. Point it at your own Mermaid bundle — one that calls registerIconPacks() with the AWS pack before initialising — and the icons would in principle resolve, because you have replaced the script Doxygen loads with one that knows about the packs.
We have not tested this and would not recommend it as a documentation strategy. You would be maintaining a custom Mermaid build, hosting it somewhere your readers can reach, keeping it in step with Doxygen's expectations about how that script initialises, and accepting that the diagrams break for any offline reader. That is a lot of moving parts for a picture that does not change often.
How do you publish an AWS architecture diagram in Doxygen today?
Export it and include it as an image. Doxygen has had a perfectly good mechanism for this all along.
Author and validate the diagram first — this is the reference architecture from our validation guide, correct on every placement and every edge:
architecture-beta
service users(aws:res-users-light)[Users]
service internet(aws:res-internet-alt1-light)[Internet]
group account(aws:aws-account)[AWS Account]
group region(aws:region)[us-east-1] in account
service s3(aws:arch-amazon-simple-storage-service)[Assets S3] in region
group vpc(aws:virtual-private-cloud-vpc)[VPC] in region
service igw(aws:res-amazon-vpc-internet-gateway)[Internet Gateway] in vpc
service alb(aws:res-elastic-load-balancing-application-load-balancer)[Load Balancer] in vpc
group pub(aws:public-subnet)[Public Subnet] in vpc
service nat(aws:res-amazon-vpc-nat-gateway)[NAT Gateway] in pub
group priv(aws:private-subnet)[Private Subnet] in vpc
service app(aws:arch-amazon-ec2)[App Server] in priv
group data(aws:private-subnet)[Data Subnet] in vpc
service db(aws:arch-amazon-rds)[RDS Database] in data
users:R --> L:internet
internet:R --> L:igw
igw:B --> T:alb
alb:B --> T:app
app:R --> L:db
app:B --> T:nat
nat:R --> T:igw
app:L --> R:s3Export it as SVG or PNG, commit both halves, and reference the image:
/**
* @page architecture System architecture
*
* @image html architecture.svg "Production AWS architecture" width=800px
* @image latex architecture.pdf "Production AWS architecture"
*
* Diagram source: `docs/diagrams/architecture.mmd`
*/Point IMAGE_PATH at the directory holding it:
IMAGE_PATH = docs/diagramsKeeping the .mmd next to the exported image is what makes this maintainable rather than a screenshot graveyard — the source diffs in review, and the next person to change the architecture has something to edit. It is the same source-plus-image pattern that works on every other platform, which is the point: one workflow, no per-platform special cases.
What if you are stuck on Doxygen 1.16 or older?
Upgrading is the real answer, but if you cannot, three routes predate native support:
ALIASESplus a customHTML_HEADER. Define an alias that emits a<pre class="mermaid">block and load mermaid.js from your header. This is what most pre-1.17 setups did, and community repositories such astttapa/doxygen-mermaidandNotgnoshi/doxygen-mermaidpackage the pieces.FILTER_PATTERNSpreprocessing. Run a script over your sources before Doxygen sees them, converting Mermaid blocks into whatever markup you want. More control, more to maintain.- Pre-rendered images. The
\imageroute above. It works on every Doxygen version ever released, needs no configuration beyondIMAGE_PATH, and is the only one of the three that handles cloud icons.
That last point is the practical case for images even after you upgrade: for cloud architecture specifically, the workflow you would use on 1.16 is the same one you use on 1.17.
Should you use Graphviz, PlantUML, or Mermaid?
Doxygen now supports three diagramming systems and they are not competing for the same work.
| Best for | Authored | Portable outside Doxygen | |
|---|---|---|---|
| Graphviz (dot) | Call graphs, include graphs, inheritance — generated from your code | Automatically by Doxygen | Somewhat |
| PlantUML | Detailed UML: sequence, class, state, component | By hand, .puml | Yes |
| Mermaid | Quick hand-drawn flow, state, and sequence diagrams | By hand, .mmd | Yes, widely |
Keep Graphviz on for the graphs Doxygen derives from your source; nothing else does that job. Reach for Mermaid when you are explaining a design decision in prose and want a diagram in the same breath — its advantage over PlantUML is not expressiveness but reach, since the same .mmd renders on GitHub and GitLab without a toolchain. And for cloud architecture, author it where the icon packs live and include the export.
Frequently asked questions
Does Doxygen support Mermaid diagrams?
Yes, natively, as of Doxygen 1.17.0 released on 30 April 2026. Before that release there was no native support and Mermaid required community workarounds. Doxygen 1.17.0 added the @mermaid and @endmermaid block commands for inline diagrams, @mermaidfile for external .mmd files, and five configuration options: MERMAID_PATH, MERMAID_CONFIG_FILE, MERMAID_RENDER_MODE, MERMAID_JS_URL and MERMAIDFILE_DIRS.
Which Doxygen version added Mermaid support?
Doxygen 1.17.0, released 30 April 2026. Run doxygen --version to check what you have. On 1.16.x or older there are no Mermaid commands at all, so you either upgrade or use one of the community approaches — an ALIASES entry plus a custom HTML_HEADER that loads mermaid.js, a FILTER_PATTERNS preprocessing script, or a pre-rendered image.
What is the difference between MERMAID_RENDER_MODE CLI and client-side rendering?
In the default client-side mode Doxygen injects a script tag pointing at MERMAID_JS_URL, and the reader's browser renders each diagram on page load. With MERMAID_RENDER_MODE set to CLI, Doxygen instead shells out to mermaid-cli at MERMAID_PATH during the documentation build and embeds the finished image, so no Mermaid JavaScript is loaded at all.
Why does Doxygen load mermaid.js when my project has no diagrams?
This is a known issue in 1.17.0: Doxygen includes the Mermaid JavaScript resources in HTML output even for projects with no Mermaid diagrams, and because the default MERMAID_JS_URL points at a CDN, offline readers see noticeable UI lag while the browser tries to fetch it. Setting MERMAID_RENDER_MODE to CLI avoids importing the JavaScript entirely.
Does Doxygen render AWS architecture diagrams with cloud icons?
No. Mermaid's architecture-beta diagram type only draws cloud icons when the renderer registers an icon pack through registerIconPacks(), which is a JavaScript API call rather than a configuration value. Neither Doxygen render mode does this, and MERMAID_CONFIG_FILE takes a Mermaid config file, which has no field for registering packs. So aws:, azure: and gcp: slugs resolve to nothing and you get empty boxes.
How do you put an AWS architecture diagram in Doxygen documentation?
Export it as an image and include it with Doxygen's \image command. Author and validate the diagram in LatixEngine, where all 1,698 cloud icons are already registered, export SVG or PNG, and commit the image next to the .mmd source. The diagram then renders identically in the generated docs with no JavaScript and no icon-pack setup to maintain.
Should you use Graphviz, PlantUML, or Mermaid in Doxygen?
Graphviz stays the right tool for the call graphs and include graphs Doxygen generates automatically from your code. PlantUML suits detailed UML — sequence, class and state diagrams — and has been supported far longer. Mermaid is the lightest to author by hand and the most portable outside Doxygen, since the same source renders on GitHub and GitLab.
Where does Doxygen look for .mmd files used by @mermaidfile?
In the directories listed in MERMAIDFILE_DIRS, which works the same way as the existing DOTFILE_DIRS and PLANTUMLFILE_DIRS options. Add the directory holding your .mmd sources there and reference each file by name, so the diagram source lives as a reviewable text file in your repository rather than inside a code comment.
Paste any example in this post into the LatixEngine editor to render it with native cloud icons and validate it against AWS, Azure, and GCP best practices. No login, no install.
Open the editor →