# Adding Mermaid Diagrams to Rehype in Astro (With rehype-mermaid-cli)

Source: https://dteather.com/blogs/astro-rehype-mermaid-cli/
Author: David Teather
Published: 2025-08-25
Updated: 2026-07-05
Description: Render UML and system design diagrams in Astro using rehype-mermaid-cli. Covers setup, light/dark mode, and comparisons with rehype-mermaid.
Categories: tutorials
Agent context: This is the Markdown source for a technical blog post. Use the source URL for citation, and use the HTML page when interactive demos, charts, images, or videos are relevant.

I just recently updated how I render UML diagrams in my blog. Originally, I used [rehype-mermaid](https://github.com/remcohaszing/rehype-mermaid) ([original blog post](./2024-10-06-astro-uml-diagrams.md)), which works by running Mermaid inside a [playwright](https://playwright.dev/python/) instance at build time. That generally was working fine for me, but I noticed that old diagrams started to render incorrectly, and I was facing issues in particular with the `sequenceDiagram` type and it started throwing this error `Error: svg element not in render tree`.

So, I decided to switch over to [mermaid-cli](https://github.com/mermaid-js/mermaid-cli) in my build time. This approach still uses [puppeteer](https://pptr.dev/) but has been more reliable for me so far, although it's still early days of the approach.

Here's an example graph with just text

```mermaid
graph TD;
    A-->B;
    A-->C;
    B-->D;
    C-->D;
```

But I also wanted to support images, which I did cover in the [previous blog post](./2024-10-06-astro-uml-diagrams.md) but will re-cover here as well.

```mermaid
 flowchart LR
     A[<img src='/icons/dead-bird.svg' width='50' height='50' /> ]
     A --> B[<img src='/icons/worm.svg' width='50' height='50' /> ]
```

## Why Use mermaid-cli?

Benefits of mermaid-cli:

- Official CLI maintained by the Mermaid team (so less chance of regressions when Mermaid itself updates or dependencies).
- More out of the box control over the output (themes, background color, SVG IDs, etc.).
  - This fixed an issue I was facing when using rehype-mermaid with inlining svgs
- More predictable builds (hopefully 🤞)

Drawbacks:

- Build-time only: mermaid-cli is a CLI only tool, so there’s no option to do live client-side rendering in the browser.
- Slower than rehype-mermaid, which makes `npm run dev` a little painful if you’re editing diagrams often.
  - We cache the results, so if you're not actively modifying your mermaid diagrams the speed is unchanged

For me these tradeoffs are worth it, if they're not acceptable for your use case try the approach in my [blog post on using rehype-mermaid](./2024-10-06-astro-uml-diagrams.md).

## Installing rehype-mermaid-cli

Initially in this article I was just going to dump [the code](https://github.com/davidteather/rehype-mermaid-cli/blob/v0.1.0/src/index.ts) on you, but I decided to make it a little bit easier to follow and created my very first npm package of [rehype-mermaid-cli](https://github.com/davidteather/rehype-mermaid-cli/tree/v0.1.0).

```bash
npm install rehype-mermaid-cli
```

## Setting Up rehype-mermaid-cli in Astro

You'll need to add this to your rehype plugins in your astro config file.

```js title="astro.config.mjs"
import { rehypeMermaidCLI } from "rehype-mermaid-cli";

export default defineConfig({
    // ...
    markdown: {
        rehypePlugins: [..., rehypeMermaidCLI ,...]
    }
    // ...
})
```

That's all you need to do! In your markdown files, you should now be able to render a markdown file like this

````
```mermaid
graph TD;
    A-->B;
    A-->C;
    B-->D;
    C-->D;
```
````

:::note
If you run into rendering issues, try installing [mermaid-cli](https://github.com/mermaid-js/mermaid-cli) globally with `npm install -g @mermaid-js/mermaid-cli`

## Adding Custom Classes

On my blog I like to add an `mx-auto` to my SVGs

```js title="astro.config.mjs"
import { rehypeMermaidCLI } from "rehype-mermaid-cli";

export default defineConfig({
    // ...
    markdown: {
        rehypePlugins: [..., [rehypeMermaidCLI, {
            svgClassNames: ["mx-auto"]
        }] ,...]
    }
    // ...
})
```

## Light vs Dark Toggle

By default this will render and inline the `default` theme on mermaid. But what if we also want to render a dark mode svg to use if the site is set to toggled to dark mode?

```js title="astro.config.mjs"
import { rehypeMermaidCLI } from "rehype-mermaid-cli";

export default defineConfig({
    // ...
    markdown: {
        rehypePlugins: [..., [rehypeMermaidCLI, {
            // renders out each theme as a separate inlined-svg
            renderThemes: ['default', 'dark']
        }] ,...]
    }
    // ...
})
```

The plugin adds class names with the themes like `mermaid mermaid-default` and `mermaid mermaid-dark`, which then you can manage in however you're currently managing your theme toggler either as css or a script that might look something like this.

```js
function updateMermaidTheme() {
    const dataTheme =
        document.documentElement.getAttribute("data-theme") || "light";
        document.querySelectorAll(".mermaid-default").forEach((el) => {
        el.style.display = dataTheme === "dark" ? "none" : "block";
        });
        document.querySelectorAll(".mermaid-dark").forEach((el) => {
        el.style.display = dataTheme === "dark" ? "block" : "none";
        });
    }

    // Listen for theme changes
    document.addEventListener("themechange", updateMermaidTheme);
}
```

## Adding SVG Support

Ok so here's where most of the hacky solutions come in for generating the diagrams. If you have better solutions please let me know.

Notes:

- Hacky; doesn't cover all SVG edge cases
- Only works with SVGs
- I didn't want to just link to a public host since I wanted to develop it locally and test it

I wanted to be able to support images like the following.

```mermaid
 flowchart LR
     A[<img src='/icons/dead-bird.svg' width='50' height='50' /> ]
     A --> B[<img src='/icons/worm.svg' width='50' height='50' /> ]
```

The code for this is this, this only supports svgs and the `icons` folder is at the astro `public/icons` folder.

````
```mermaid
 flowchart LR
     A[<img src='/icons/dead-bird.svg' width='50' height='50' /> ]
     A --> B[<img src='/icons/worm.svg' width='50' height='50' /> ]
```
````

Unfortunately I solved this with yet another rehype extension, but this time it's a preprocessor that will read the svg file and inline the contents of it into the mermaid code.

It's pretty messy but here's a link to the function [on github](https://gist.github.com/davidteather/91c0e02120897d4b2b8376a351420474)

It could be worse, but it’s admittedly a bit sloppy. Then add it **before** our mermaid-cli rehype plugin

```js title="astro.config.mjs"
import { rehypeMermaidCLI } from "rehype-mermaid-cli";

export default defineConfig({
    // ...
    markdown: {
        rehypePlugins: [..., rehypeInlineSvg, [rehypeMermaidCLI, {
            // renders out each theme as a separate inlined-svg
            renderThemes: ['default', 'dark']
        }] ,...]
    }
    // ...
})
```

## Updating Deployment

The mermaid-cli tool uses [puppeteer](https://pptr.dev/), you can find other articles on how to get this to properly run on your CI tool but you'll likely at least need to specify headless=True and --no-sandbox.

```js title="astro.config.mjs"
import { rehypeMermaidCLI } from "rehype-mermaid-cli";

export default defineConfig({
    // ...
    markdown: {
        rehypePlugins: [..., rehypeInlineSvg, [rehypeMermaidCLI, {
            puppeteerConfig: {
                headless: 1,
                args: ["--no-sandbox"]
            }
        }] ,...]
    }
    // ...
})
```

Hope this helps! If you want more options / features or run into bugs on the [rehype-mermaid-cli](https://github.com/davidteather/rehype-mermaid-cli) tool feel free to create an issue on the GitHub repo or submit a PR.
