<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Levi Liu</title>
    <description>The latest articles on DEV Community by Levi Liu (@levi_liu).</description>
    <link>https://dev.to/levi_liu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3923265%2Ffe4d37ec-b536-47ca-961f-52b899ecf158.png</url>
      <title>DEV Community: Levi Liu</title>
      <link>https://dev.to/levi_liu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/levi_liu"/>
    <language>en</language>
    <item>
      <title>Beautify Every Diagram in Your Markdown Docs with One Command</title>
      <dc:creator>Levi Liu</dc:creator>
      <pubDate>Tue, 16 Jun 2026 14:39:26 +0000</pubDate>
      <link>https://dev.to/levi_liu/beautify-every-diagram-in-your-markdown-docs-with-one-command-kdp</link>
      <guid>https://dev.to/levi_liu/beautify-every-diagram-in-your-markdown-docs-with-one-command-kdp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;
A typical docs repo has dozens of Mermaid blocks scattered across markdown files, each rendering with whatever default Mermaid theme the consumer site picked, none of them consistent with each other. This post walks the two-command path — &lt;code&gt;bd extract&lt;/code&gt; to pull every fenced block out of markdown, &lt;code&gt;bd batch&lt;/code&gt; to render them all to themed SVGs, and a small markdown rewrite to embed the SVGs back via &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;. The same pipeline drops into a GitHub Actions workflow at the end. If you want to try a single file first, the &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;editor&lt;/a&gt; renders one block at a time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The state of diagrams in most docs repos
&lt;/h2&gt;

&lt;p&gt;Open any mid-sized open-source repo with substantial docs — &lt;code&gt;kubernetes/kubernetes&lt;/code&gt;, &lt;code&gt;prometheus/prometheus&lt;/code&gt;, &lt;code&gt;vercel/next.js&lt;/code&gt;. Search the markdown tree for &lt;code&gt;mermaid&lt;/code&gt; fenced blocks. You'll find 30 to 100 of them across docs, contributing guides, RFC archives, and stale design notes.&lt;/p&gt;

&lt;p&gt;Then look at how those diagrams actually render. Three observations, every time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Most diagrams use Mermaid's default theme&lt;/strong&gt; — the pastel one with the muted blues and the soft drop-shadows. It's fine in isolation. Across 40 diagrams in a single docs site, it reads as "nobody owned this."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some diagrams are silently broken.&lt;/strong&gt; A typo in a &lt;code&gt;flowchart&lt;/code&gt; arrow, an unclosed &lt;code&gt;subgraph&lt;/code&gt;, an &lt;code&gt;erDiagram&lt;/code&gt; field that no longer parses on the current Mermaid version. The page renders, the diagram block becomes an error message, nobody notices for six months because nobody reads the contributing guide that often.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The diagrams that DO look good are the recent ones.&lt;/strong&gt; Whoever shipped them most recently set a theme in an &lt;code&gt;init&lt;/code&gt; block at the top of the diagram. Older blocks don't have the directive. The site looks like geological strata of "whatever Mermaid theme was fashionable that quarter."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can fix all three by hand. Open every markdown file, paste each Mermaid block into a renderer, eyeball it, fix syntax errors, prepend an &lt;code&gt;init&lt;/code&gt; directive with your preferred theme, save. For a 60-file docs repo that's maybe a day of mechanical work — and it'll drift again in three months because every new contributor adds blocks without the directive.&lt;/p&gt;

&lt;p&gt;Or you can build a two-command pipeline that does this automatically and run it in CI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0uutp5bj0zwcxpe3zw1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0uutp5bj0zwcxpe3zw1.png" alt="A flowchart showing markdown docs feeding into bd extract, which feeds bd batch, which produces themed SVGs, which get embedded back into the markdown via the picture element" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The pipeline this post builds: extract every fenced diagram out of markdown, render them all in one batch, embed the SVGs back so the rendered page shows your themed version while the markdown source still holds the original code.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why bake the SVG into the page (instead of letting the site render Mermaid live)
&lt;/h2&gt;

&lt;p&gt;A reasonable counter-argument: "My doc site already renders Mermaid client-side via mermaid.js. Why pre-render at all?"&lt;/p&gt;

&lt;p&gt;Three reasons the pre-render path wins for docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency across surfaces.&lt;/strong&gt; Your README on GitHub, your VS Code marketplace listing, your npm page, your Docusaurus site, your printed PDF export — all render Mermaid differently (or not at all). A pre-rendered SVG looks the same everywhere because there's no rendering left to do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bundle weight.&lt;/strong&gt; mermaid.js minified is around 600 KB. If the only reason your docs ship it is the four diagrams on your architecture page, you're paying a meaningful payload tax for every visitor of every other page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The diagram becomes a real asset.&lt;/strong&gt; Once it's an SVG on disk you can review it in PRs (the diff is the SVG file, which renders in GitHub's PR view), you can run an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; accessibility check on it, and you can link to it from outside the docs site.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pipeline below keeps the Mermaid source in the markdown — so contributors still edit Mermaid, not SVG — but renders to an SVG asset alongside it. The &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; embed shows the SVG to readers; the source block becomes a collapsed &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; for anyone who wants to see the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — &lt;code&gt;bd extract&lt;/code&gt; pulls every diagram out of markdown
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @beauty-diagram/cli extract docs/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.md &lt;span class="nt"&gt;--assets-dir&lt;/span&gt; docs/_diagrams
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This walks every markdown file matching the glob, finds every fenced &lt;code&gt;mermaid&lt;/code&gt; (and &lt;code&gt;plantuml&lt;/code&gt;) block, and writes each one to a standalone source file under the assets directory. Filename is derived from the markdown file path plus a stable hash of the block contents, so re-running on an unchanged docs tree is a no-op.&lt;/p&gt;

&lt;p&gt;A typical output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/_diagrams/
  architecture/
    overview-a3f9c1.mmd
    overview-b8e240.mmd
    auth-flow-7c2105.mmd
  contributing/
    pr-lifecycle-91d8a2.mmd
  guides/
    request-path-4e1c80.mmd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few flags worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--dry-run&lt;/code&gt; lists what would be written without touching disk. Run this first to see how many blocks your repo actually has.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--clean&lt;/code&gt; removes orphaned source files in the assets directory before extracting — useful when blocks get deleted from markdown and you don't want stale &lt;code&gt;.mmd&lt;/code&gt; files lying around.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--concurrency &amp;lt;n&amp;gt;&lt;/code&gt; controls parallel parsing for very large doc trees. The default is sensible; only touch it if you're indexing thousands of files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a block has a syntax error, &lt;code&gt;bd extract&lt;/code&gt; still writes the source file and prints a warning. The block is real even if it's broken; the next step decides what to do with broken blocks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — &lt;code&gt;bd batch&lt;/code&gt; renders them all to themed SVGs
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @beauty-diagram/cli batch docs/_diagrams/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.mmd &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--out-dir&lt;/span&gt; docs/_diagrams &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--format&lt;/span&gt; svg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This renders every extracted source file to an SVG sibling. Same filename, different extension. Theme is whichever one you set globally — &lt;code&gt;BEAUTY_DIAGRAM_THEME=modern&lt;/code&gt; in the environment, or passed per-file via the source's own &lt;code&gt;init&lt;/code&gt; directive.&lt;/p&gt;

&lt;p&gt;You'll get output like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ docs/_diagrams/architecture/overview-a3f9c1.svg (1142×680)
✓ docs/_diagrams/architecture/overview-b8e240.svg (980×420)
✓ docs/_diagrams/architecture/auth-flow-7c2105.svg (1240×910)
✗ docs/_diagrams/contributing/pr-lifecycle-91d8a2.mmd: parse error at line 14
✓ docs/_diagrams/guides/request-path-4e1c80.svg (860×540)

4 succeeded, 1 failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--stop-on-error&lt;/code&gt; flag flips the failure mode: by default &lt;code&gt;bd batch&lt;/code&gt; keeps going so one bad diagram doesn't tank a 200-diagram run. In CI you'll usually want &lt;code&gt;--stop-on-error&lt;/code&gt; so a broken block fails the build, which is the whole point of running this in CI to begin with.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--concurrency&lt;/code&gt; defaults to a reasonable parallelism for your CPU; raise it on a big CI runner if the batch takes long enough to matter.&lt;/p&gt;

&lt;p&gt;The "consistency" payoff lands here. The same theme renders every diagram across the entire docs tree.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4iccdm2glt8tb6t3tm0p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4iccdm2glt8tb6t3tm0p.png" alt="A four-node architecture flow — API Gateway, Auth Service, App Services, Event Bus — rendered with the modern theme" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A typical architecture diagram rendered with a single chosen theme. The consistency story is that every one of your 40 docs diagrams comes out looking like this one — same stroke weight, same palette, same edge style.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Embed the SVGs back via &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The extract / batch pair gave you SVG files. The markdown still holds the original Mermaid source. Now you decide how the rendered page should reference the asset.&lt;/p&gt;

&lt;p&gt;The cleanest pattern is &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; with the SVG as the primary source and a collapsed &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; for the original code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &amp;lt;img
    src="/_diagrams/architecture/overview-a3f9c1.svg"
    alt="High-level system architecture: API gateway, auth service, app services, and the shared event bus"
  /&amp;gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;details&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;Mermaid source&lt;span class="nt"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;mermaid
&lt;/span&gt;&lt;span class="sb"&gt;flowchart LR
  Gateway[API Gateway] --&amp;gt; Auth[Auth Service]
  Gateway --&amp;gt; App[App Services]
  App --&amp;gt; Bus[(Event Bus)]&lt;/span&gt;
&lt;span class="p"&gt;```&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/details&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this shape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The reader sees the SVG by default&lt;/strong&gt; — themed, crisp, no client-side rendering cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The source is one click away&lt;/strong&gt; for anyone who wants to copy it into their own diagram, file a fix, or learn from the syntax.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The markdown file remains the source of truth.&lt;/strong&gt; A contributor editing the doc edits the Mermaid block, runs the pipeline, commits both the updated source and the regenerated SVG.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most static site generators (Docusaurus, VitePress, MkDocs, Hugo, Astro) render &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; natively. GitHub's markdown renderer does too, including in PR descriptions. The pattern is portable.&lt;/p&gt;

&lt;p&gt;If you'd rather not maintain the dual source + asset embed by hand, the extract step has a &lt;code&gt;--rewrite&lt;/code&gt; mode that updates the markdown file in place — collapsing the fenced block into the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; + &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; pair on first run, leaving it alone on subsequent runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Wire it into CI so it stays beautified
&lt;/h2&gt;

&lt;p&gt;A small GitHub Actions workflow that fails any PR introducing a broken diagram or skipping the regeneration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Beautify docs&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;docs/**/*.md'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;docs/_diagrams/**'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;beautify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Extract diagrams from markdown&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;npx @beauty-diagram/cli extract 'docs/**/*.md' \&lt;/span&gt;
            &lt;span class="s"&gt;--assets-dir docs/_diagrams \&lt;/span&gt;
            &lt;span class="s"&gt;--clean&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Render every diagram&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;npx @beauty-diagram/cli batch 'docs/_diagrams/**/*.mmd' \&lt;/span&gt;
            &lt;span class="s"&gt;--out-dir docs/_diagrams \&lt;/span&gt;
            &lt;span class="s"&gt;--format svg \&lt;/span&gt;
            &lt;span class="s"&gt;--stop-on-error&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;BEAUTY_DIAGRAM_THEME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;modern&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fail if anything changed&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;git diff --exit-code docs/_diagrams || (&lt;/span&gt;
            &lt;span class="s"&gt;echo "::error::Diagrams are out of date. Run the beautify pipeline locally and commit the result."&lt;/span&gt;
            &lt;span class="s"&gt;exit 1&lt;/span&gt;
          &lt;span class="s"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;git diff --exit-code&lt;/code&gt; at the end is the trick. The job regenerates everything from scratch on every PR; if the output differs from what's checked in, the PR failed to run the pipeline before pushing, and the build fails. Contributors learn the workflow once and it stays automatic forever.&lt;/p&gt;

&lt;p&gt;For a &lt;code&gt;Makefile&lt;/code&gt;-driven repo, the same pattern collapses to two targets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;diagrams&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    npx @beauty-diagram/cli extract &lt;span class="s1"&gt;'docs/**/*.md'&lt;/span&gt; &lt;span class="nt"&gt;--assets-dir&lt;/span&gt; docs/_diagrams &lt;span class="nt"&gt;--clean&lt;/span&gt;
    npx @beauty-diagram/cli batch &lt;span class="s1"&gt;'docs/_diagrams/**/*.mmd'&lt;/span&gt; &lt;span class="nt"&gt;--out-dir&lt;/span&gt; docs/_diagrams &lt;span class="nt"&gt;--format&lt;/span&gt; svg &lt;span class="nt"&gt;--stop-on-error&lt;/span&gt;

&lt;span class="nl"&gt;verify-diagrams&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;diagrams&lt;/span&gt;
    git diff &lt;span class="nt"&gt;--exit-code&lt;/span&gt; docs/_diagrams
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;make diagrams&lt;/code&gt; regenerates locally; &lt;code&gt;make verify-diagrams&lt;/code&gt; is what CI calls.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;From one file to a whole repo: themed SVGs for every diagram, in one batch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.beauty-diagram.com" rel="noopener noreferrer"&gt;Beauty Diagram&lt;/a&gt;'s CLI ships extract + batch as the docs-scale pair, so the same renderer that handles a single file in the editor handles a hundred files in CI. Pick a theme once, apply it everywhere, and let the git-diff check keep contributors honest. &lt;em&gt;(Disclosure: I work on it.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;→ Try one diagram in the editor&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The fastest way to feel the workflow is one file at a time in the &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;editor&lt;/a&gt; — paste a Mermaid block from your docs repo, pick a theme, see whether the result is the consistency you want. Once you've picked a theme you like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install once&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; @beauty-diagram/cli

&lt;span class="c"&gt;# Set the theme for the whole repo&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BEAUTY_DIAGRAM_THEME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;modern

&lt;span class="c"&gt;# Run the pipeline locally&lt;/span&gt;
npx bd extract &lt;span class="s1"&gt;'docs/**/*.md'&lt;/span&gt; &lt;span class="nt"&gt;--assets-dir&lt;/span&gt; docs/_diagrams &lt;span class="nt"&gt;--clean&lt;/span&gt;
npx bd batch &lt;span class="s1"&gt;'docs/_diagrams/**/*.mmd'&lt;/span&gt; &lt;span class="nt"&gt;--out-dir&lt;/span&gt; docs/_diagrams &lt;span class="nt"&gt;--format&lt;/span&gt; svg

&lt;span class="c"&gt;# Commit the assets and the rewritten markdown&lt;/span&gt;
git add docs/_diagrams docs/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.md
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Beautify docs diagrams"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bd beautify&lt;/code&gt;, &lt;code&gt;bd export&lt;/code&gt;, &lt;code&gt;bd extract&lt;/code&gt;, and &lt;code&gt;bd batch&lt;/code&gt; all work anonymously for rendering. The paid tier kicks in for AI features (&lt;code&gt;bd ai generate&lt;/code&gt;) and higher quotas; the docs-pipeline use case lives entirely inside the free surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  When NOT to pre-render
&lt;/h2&gt;

&lt;p&gt;A few cases where the live-Mermaid-in-the-browser path is the better trade:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Your docs site already ships mermaid.js for other reasons.&lt;/strong&gt; If the bundle cost is paid, you're not saving anything by pre-rendering. Use &lt;code&gt;init&lt;/code&gt; directives in your Mermaid blocks to set a consistent theme and call it done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagrams change every commit.&lt;/strong&gt; A README that auto-regenerates an architecture diagram from the codebase on every push has no use for pre-rendered assets — the SVG would be stale by the next push. Live rendering at view time is the right call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You only have three diagrams.&lt;/strong&gt; The batch pipeline pays off when there are enough diagrams that consistency is the problem. Three diagrams you can keep coherent by hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your audience needs the source visible by default.&lt;/strong&gt; A Mermaid tutorial, a "diagrams as code" RFC, a contributing guide. Pre-rendering hides the syntax behind a &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;; if the syntax IS the point, leave it as a fenced block.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The rule of thumb: pre-render when the diagram is a doc asset (read, not edited, by most readers); live-render when the diagram is the doc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;Three takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Diagrams in docs repos drift the same way docs drift.&lt;/strong&gt; Different themes, broken blocks, no review process. The fix is the same fix you applied to docs: a build step + a CI gate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The two-command pipeline is &lt;code&gt;bd extract&lt;/code&gt; + &lt;code&gt;bd batch&lt;/code&gt;.&lt;/strong&gt; Extract pulls every fenced block to standalone source files; batch renders all of them to themed SVGs. The git-diff CI check keeps the output in sync.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embed via &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; + collapsed &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;.&lt;/strong&gt; Reader sees the themed SVG, contributor still edits Mermaid, source of truth stays in markdown.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this was useful, drop a ❤️ and follow — I'm posting weekly on diagrams, docs, and developer ergonomics. Next week: &lt;strong&gt;Beautify Mermaid Diagrams in Obsidian and VS Code (Without Leaving Your Editor)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;How many Mermaid blocks does your docs repo have right now? Run &lt;code&gt;grep -r "mermaid" docs/ | wc -l&lt;/code&gt; and drop the number in the comments — I'm collecting "diagrams per docs repo" data and the spread is wider than you'd guess.&lt;/p&gt;

</description>
      <category>mermaid</category>
      <category>documentation</category>
      <category>cli</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Generate Mermaid from Plain English with AI (CLI Walkthrough)</title>
      <dc:creator>Levi Liu</dc:creator>
      <pubDate>Wed, 10 Jun 2026 09:43:31 +0000</pubDate>
      <link>https://dev.to/levi_liu/generate-mermaid-from-plain-english-with-ai-cli-walkthrough-4ii0</link>
      <guid>https://dev.to/levi_liu/generate-mermaid-from-plain-english-with-ai-cli-walkthrough-4ii0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;
You already know &lt;code&gt;flowchart TD&lt;/code&gt; cold. You don't know &lt;code&gt;sequenceDiagram&lt;/code&gt; participant aliases, &lt;code&gt;erDiagram&lt;/code&gt; cardinality glyphs, or which state diagram dialect Mermaid is on this year. This post is a walkthrough of five prompts → five diagrams using &lt;code&gt;bd ai generate&lt;/code&gt;, plus when the AI-first path is wrong. If you want to try without installing anything, the same prompt input lives in the &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;editor&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The friction isn't drawing — it's remembering
&lt;/h2&gt;

&lt;p&gt;I've shipped probably 200 flowcharts. I can sketch a &lt;code&gt;flowchart TD&lt;/code&gt; with arrows and labels without thinking. The syntax has lived in my hands long enough that it's muscle memory.&lt;/p&gt;

&lt;p&gt;Then someone asks for a sequence diagram of the OAuth flow, and I open the Mermaid docs. Again. For the seventh time this year.&lt;/p&gt;

&lt;p&gt;That's the actual friction with diagrams-as-code: most teams write one diagram type 90% of the time and four other types maybe twice a year each. The rare types never make it into your fingers — you re-read the docs every time, hit a syntax snag, and lose ten minutes. Multiply by every infrequent diagram across a docs repo and that's a real tax.&lt;/p&gt;

&lt;p&gt;AI removes the activation energy. You describe the diagram in plain English, get back syntactically valid Mermaid, and skip straight to "does this say what I want." That's a different kind of editing — refining a draft instead of looking up glyphs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfdi9do1gd7pdlx8orpc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfdi9do1gd7pdlx8orpc.png" alt="A flowchart showing plain English prompt feeding into AI, producing Mermaid source, which is rendered into a polished SVG" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The path this post walks: prompt → AI → Mermaid → rendered diagram.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of the workflow
&lt;/h2&gt;

&lt;p&gt;Two paths, same engine underneath:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;In the editor&lt;/strong&gt; — paste your prompt into the AI Generate panel at &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;/editor&lt;/a&gt;. It writes the Mermaid for you, you tweak in the source pane, you pick a theme, you export.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In the terminal&lt;/strong&gt; — &lt;code&gt;bd ai generate "&amp;lt;prompt&amp;gt;"&lt;/code&gt; prints the Mermaid to stdout. Pipe it into the renderer, redirect to a file, or paste into your README.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The editor is the right entry point if you're iterating — you can see the rendered diagram live as you refine the source. The CLI is the right surface once you know what you want and you're scripting it into a docs build, a &lt;code&gt;package.json&lt;/code&gt; task, or a CI job.&lt;/p&gt;

&lt;p&gt;The five examples below all use the CLI form so the prompts and outputs are easy to copy. Every one of them works in the editor too — paste the same prompt, get the same kind of output.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bd ai generate&lt;/code&gt; is a paid-plan feature. Anonymous demo gives you the renderer; AI generation is gated behind a key because every call hits a model and costs money. &lt;code&gt;bd auth login&lt;/code&gt; once, set &lt;code&gt;BEAUTY_DIAGRAM_API_KEY&lt;/code&gt; in CI, done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 1 — OAuth login (sequence diagram)
&lt;/h2&gt;

&lt;p&gt;Sequence diagrams are the textbook case for "I know what I want, I don't remember the syntax." Participants, arrows, dotted return lines, &lt;code&gt;loop&lt;/code&gt; blocks — there's just enough surface to forget between uses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bd ai generate &lt;span class="s2"&gt;"user signs in with Google OAuth: web app redirects &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
to Google's authorize endpoint, user approves, Google returns an &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
authorization code, web app exchanges the code at our API for a &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
session token"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI returns something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sequenceDiagram
  participant U as User
  participant W as Web App
  participant G as Google OAuth
  participant A as App API
  U-&amp;gt;&amp;gt;W: Click "Sign in with Google"
  W-&amp;gt;&amp;gt;G: Redirect to /authorize
  G-&amp;gt;&amp;gt;U: Consent prompt
  U-&amp;gt;&amp;gt;G: Approve scopes
  G-&amp;gt;&amp;gt;W: Authorization code
  W-&amp;gt;&amp;gt;A: Exchange code
  A-&amp;gt;&amp;gt;W: Session token
  W-&amp;gt;&amp;gt;U: Logged in
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Render it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe785flbl59tknj9v3f3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe785flbl59tknj9v3f3.png" alt="A sequence diagram showing the OAuth authorization-code flow between User, Web App, Google OAuth, and the App API" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;OAuth authorization-code flow, generated from the prompt above and rendered with the &lt;code&gt;atlas&lt;/code&gt; theme.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The participants are aliased (&lt;code&gt;U as User&lt;/code&gt;, &lt;code&gt;W as Web App&lt;/code&gt;) without me having to remember the syntax. The arrows pick &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt; for solid calls. Two minutes from prompt to rendered diagram, of which ten seconds was renaming "App API" to "Backend" to match the codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 2 — Multi-tenant SaaS schema (ER diagram)
&lt;/h2&gt;

&lt;p&gt;ER diagrams are the worst offender for syntax recall. Cardinality glyphs — &lt;code&gt;||--o{&lt;/code&gt;, &lt;code&gt;}o--||&lt;/code&gt;, &lt;code&gt;|o--o|&lt;/code&gt; — never live in anyone's head.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bd ai generate &lt;span class="s2"&gt;"multi-tenant SaaS database: users belong to many &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
workspaces through memberships; workspaces own projects; projects &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
contain tasks; users are also assigned to tasks"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;erDiagram
  USERS ||--o{ MEMBERSHIPS : has
  WORKSPACES ||--o{ MEMBERSHIPS : has
  WORKSPACES ||--o{ PROJECTS : owns
  PROJECTS ||--o{ TASKS : contains
  USERS ||--o{ TASKS : assigned
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0d513ne15wsr02g2yxvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0d513ne15wsr02g2yxvq.png" alt="An ER diagram showing the relationships between Users, Memberships, Workspaces, Projects, and Tasks in a multi-tenant SaaS schema" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A multi-tenant SaaS schema, generated from a one-sentence prompt and rendered with the &lt;code&gt;blueprint&lt;/code&gt; theme.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The model picked the right cardinality glyphs without you typing them. It also picked an entity-naming convention (uppercase, plural) and stuck with it across all five entities. That's the kind of consistency tax you'd otherwise pay manually.&lt;/p&gt;

&lt;p&gt;When this matters: the diagram is wrong if &lt;code&gt;MEMBERSHIPS&lt;/code&gt; should have been an attribute on &lt;code&gt;USERS&lt;/code&gt; instead of a join entity. The AI guessed "many-to-many through membership", which is the right call for most multi-tenant SaaS — but if you're modeling something else, you'll edit. That's the workflow: get a draft fast, refine the parts that don't match your domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 3 — CI/CD pipeline (flowchart)
&lt;/h2&gt;

&lt;p&gt;Yes, even the flowchart you can write blindfolded benefits from a prompt when the diagram has six branches and a manual gate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bd ai generate &lt;span class="s2"&gt;"GitHub Actions pipeline: PR merged to main triggers &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
tests; if tests pass build a container image, deploy to staging, &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
require manual approval, then deploy to production. If tests fail, &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
notify the PR author."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
  PR[PR merged to main] --&amp;gt; Test[Run tests]
  Test --&amp;gt;|pass| Build[Build image]
  Test --&amp;gt;|fail| Notify[Notify author]
  Build --&amp;gt; Stage[Deploy to staging]
  Stage --&amp;gt; Gate{Manual approval}
  Gate --&amp;gt;|approve| Prod[Deploy to prod]
  Gate --&amp;gt;|reject| Hold[Hold release]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xl53x2yu2bnz7au3ml1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xl53x2yu2bnz7au3ml1.png" alt="A top-down flowchart showing a CI/CD pipeline from PR merge through tests, image build, staging deploy, manual approval, and prod deploy, with branches for test failure and approval rejection" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The CI/CD pipeline, with the failure branches the prompt asked for. Rendered with the &lt;code&gt;modern&lt;/code&gt; theme.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Two details worth noting. First, the AI chose &lt;code&gt;{Manual approval}&lt;/code&gt; (decision diamond) instead of &lt;code&gt;[Manual approval]&lt;/code&gt; (rectangle) for the gate — the right shape for a yes/no branch. Second, it used &lt;code&gt;--&amp;gt;|pass|&lt;/code&gt; for labelled edges instead of breaking the label onto a separate line, which is the cleaner Mermaid idiom.&lt;/p&gt;

&lt;p&gt;You could have written this. The question is whether you want to spend three minutes typing it or thirty seconds prompting it. For a diagram that's going in your team's onboarding doc and won't change for six months, the prompt path is the better trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 4 — Order lifecycle (state diagram)
&lt;/h2&gt;

&lt;p&gt;State machines are another "syntax-rare" category. &lt;code&gt;[*] --&amp;gt; X&lt;/code&gt;, transitions with labels, the difference between &lt;code&gt;stateDiagram&lt;/code&gt; and &lt;code&gt;stateDiagram-v2&lt;/code&gt; (the v2 syntax is what Mermaid currently maintains).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bd ai generate &lt;span class="s2"&gt;"order lifecycle state machine: starts in cart, &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
becomes placed on checkout, paid when payment succeeds, shipped &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
when fulfilled, delivered when the carrier confirms. From paid, &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
the customer can cancel to refunded."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stateDiagram-v2
  [*] --&amp;gt; Cart
  Cart --&amp;gt; Placed: Checkout
  Placed --&amp;gt; Paid: Payment OK
  Paid --&amp;gt; Shipped: Fulfilled
  Shipped --&amp;gt; Delivered: Carrier confirms
  Delivered --&amp;gt; [*]
  Paid --&amp;gt; Refunded: Customer cancels
  Refunded --&amp;gt; [*]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5zolqs6s267f1ftze90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5zolqs6s267f1ftze90.png" alt="A state diagram showing an order moving from Cart through Placed, Paid, Shipped, Delivered, with a branch to Refunded from Paid" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Order lifecycle states, with the refund branch the prompt described. Rendered with the &lt;code&gt;slate&lt;/code&gt; theme.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The AI picked &lt;code&gt;stateDiagram-v2&lt;/code&gt; (the current syntax), used &lt;code&gt;[*]&lt;/code&gt; for entry and exit, and put transition labels after the colon. All things I'd otherwise look up.&lt;/p&gt;

&lt;p&gt;There's a subtler thing happening: the prompt described "from paid, the customer can cancel to refunded" — a side branch from the main happy path. The AI laid it out as a separate transition rather than nesting it inside a &lt;code&gt;state Paid { ... }&lt;/code&gt; block. That's a layout decision the model made for you. If you wanted the refund flow nested, you'd add "group Paid → Refunded into a Paid composite state" to the prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt 5 — Notification class hierarchy (class diagram)
&lt;/h2&gt;

&lt;p&gt;Class diagrams are the format devs hate most. The syntax is verbose, the cardinality / inheritance arrows are easy to mix up, and you write maybe two per year.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bd ai generate &lt;span class="s2"&gt;"class hierarchy for a polymorphic notification &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
system: base Notification with channel and deliver(), then &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
EmailNotification with htmlBody and fromAddress, SmsNotification &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
with shortMessage and senderId, PushNotification with deeplink &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
and iconUrl"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;classDiagram
  class Notification {
    +String channel
    +deliver()
  }
  class EmailNotification {
    +String htmlBody
    +String fromAddress
  }
  class SmsNotification {
    +String shortMessage
    +String senderId
  }
  class PushNotification {
    +String deeplink
    +String iconUrl
  }
  Notification &amp;lt;|-- EmailNotification
  Notification &amp;lt;|-- SmsNotification
  Notification &amp;lt;|-- PushNotification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjzpag7sfc9le0fxltzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjzpag7sfc9le0fxltzs.png" alt="A class diagram showing a Notification base class with three subclasses: EmailNotification, SmsNotification, and PushNotification, each with their channel-specific fields" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Three-channel notification class hierarchy. Rendered with the &lt;code&gt;atelier&lt;/code&gt; theme.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;|--&lt;/code&gt; (empty triangle, hollow head, line) is the inheritance arrow. Reversed direction (&lt;code&gt;--|&amp;gt;&lt;/code&gt;) means the same relationship from the other end. Knowing that one glyph fluently is the difference between a 30-second class diagram and a 5-minute one. The AI knows it; you don't have to.&lt;/p&gt;

&lt;h2&gt;
  
  
  When NOT to use AI
&lt;/h2&gt;

&lt;p&gt;The prompt-to-diagram path is great for drafts. It's a worse fit for these cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The diagram already exists, you're refining it.&lt;/strong&gt; Editing five nodes by hand is faster than prompting "the same diagram but with X changed." Refinement is what the editor's source pane is for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need precise layout.&lt;/strong&gt; AI controls the &lt;em&gt;content&lt;/em&gt; (nodes, edges, labels). It doesn't control left-vs-right ordering, column widths, where the diamond lands. If a stakeholder needs the "approve" branch on the right specifically, you'll be editing the source anyway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The diagram encodes ground truth.&lt;/strong&gt; Database schemas pulled from &lt;code&gt;\dt&lt;/code&gt;, API call sequences pulled from logs, dependency graphs from your build system — pull these from the source of truth, don't have an AI guess. The AI is useful when &lt;em&gt;you're&lt;/em&gt; the source of truth and the friction is just getting it into Mermaid syntax.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're learning Mermaid.&lt;/strong&gt; If your goal is to internalize the syntax for a diagram type you'll need monthly, hand-write the first five. After that, automation is fine. Skipping the learning round costs you forever.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The rule of thumb: use AI for "I know what I want and I don't want to look up the syntax." Don't use it for "I don't know what the diagram should show yet" or "this diagram needs to be load-bearing for an audit."&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Skip the docs lookup: Prompt to rendered diagram, end to end&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.beauty-diagram.com" rel="noopener noreferrer"&gt;Beauty Diagram&lt;/a&gt;'s AI panel generates Mermaid from plain English in the same editor where you pick a theme and export — no separate AI tool, no copy-paste round trip. The same pipeline runs from the CLI for scripted use. &lt;em&gt;(Disclosure: I work on it.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;→ Try it in the editor&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The web flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the editor at &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;/editor&lt;/a&gt; and click the &lt;strong&gt;AI Generate&lt;/strong&gt; panel.&lt;/li&gt;
&lt;li&gt;Type your prompt. The model writes Mermaid into the source pane.&lt;/li&gt;
&lt;li&gt;Tweak the source if needed — rename a participant, reorder an entity, retitle an arrow.&lt;/li&gt;
&lt;li&gt;Pick a theme (&lt;code&gt;classic&lt;/code&gt;, &lt;code&gt;modern&lt;/code&gt;, &lt;code&gt;atlas&lt;/code&gt;, &lt;code&gt;blueprint&lt;/code&gt;, &lt;code&gt;memphis&lt;/code&gt;, &lt;code&gt;obsidian&lt;/code&gt;, &lt;code&gt;slate&lt;/code&gt;, &lt;code&gt;brutalist&lt;/code&gt;, or &lt;code&gt;atelier&lt;/code&gt;) and export SVG or PNG.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you'd rather script it from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Print Mermaid to stdout&lt;/span&gt;
npx @beauty-diagram/cli ai generate &lt;span class="s2"&gt;"user signup with email verification"&lt;/span&gt;

&lt;span class="c"&gt;# Pipe straight into the renderer with a theme&lt;/span&gt;
npx @beauty-diagram/cli ai generate &lt;span class="s2"&gt;"user signup with email verification"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | npx @beauty-diagram/cli beautify - &lt;span class="nt"&gt;--theme&lt;/span&gt; modern &lt;span class="nt"&gt;--out&lt;/span&gt; signup.svg

&lt;span class="c"&gt;# Or save the source and the SVG together&lt;/span&gt;
npx @beauty-diagram/cli ai generate &lt;span class="s2"&gt;"user signup with email verification"&lt;/span&gt; &lt;span class="nt"&gt;--out&lt;/span&gt; signup.mmd
npx @beauty-diagram/cli beautify signup.mmd &lt;span class="nt"&gt;--theme&lt;/span&gt; modern &lt;span class="nt"&gt;--out&lt;/span&gt; signup.svg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bd ai generate&lt;/code&gt; is paid-plan only — &lt;code&gt;bd auth login&lt;/code&gt; saves a key locally, or set &lt;code&gt;BEAUTY_DIAGRAM_API_KEY&lt;/code&gt; in CI. The renderer half (&lt;code&gt;bd beautify&lt;/code&gt;, &lt;code&gt;bd export&lt;/code&gt;) works anonymously if you only need rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;The three takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use AI for the diagram types you don't write often.&lt;/strong&gt; Sequence, ER, class, state — anything where you'd otherwise re-read the docs. Flowcharts you already write fluently; skip the AI if you don't need the speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat the output as a draft.&lt;/strong&gt; Rename, reorder, retheme. The prompt got you past the syntax wall; you still own the diagram.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two surfaces, one engine.&lt;/strong&gt; Editor for iteration, CLI for scripts. The CLI's &lt;code&gt;bd ai generate | bd beautify -&lt;/code&gt; pipe is the fastest "prompt to SVG on disk" path.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this was useful, drop a ❤️ and follow — I'm posting weekly on diagrams, docs, and developer ergonomics. Next week: &lt;strong&gt;Beautify Every Diagram in Your Markdown Docs with One Command&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What's the diagram type you re-read the docs for every time? Sequence? State? ER? Drop it in the comments — I'm building a list of "which Mermaid types people forget most" and the answers so far are surprising.&lt;/p&gt;

</description>
      <category>mermaid</category>
      <category>ai</category>
      <category>cli</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Mermaid vs PlantUML in 2026: Which to Pick for Engineering Docs</title>
      <dc:creator>Levi Liu</dc:creator>
      <pubDate>Tue, 02 Jun 2026 16:15:22 +0000</pubDate>
      <link>https://dev.to/levi_liu/mermaid-vs-plantuml-in-2026-which-to-pick-for-engineering-docs-59dm</link>
      <guid>https://dev.to/levi_liu/mermaid-vs-plantuml-in-2026-which-to-pick-for-engineering-docs-59dm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;
Mermaid won the README and the markdown ecosystem; PlantUML won the engineering whiteboard and the IDE. In 2026 they're still the two serious "diagram as code" formats, and which one you should pick depends on where the diagram lives more than what it shows. This post compares them on syntax, layout, diagram coverage, and ecosystem, ending with a decision rule you can apply in 60 seconds. Both render through the same &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;editor&lt;/a&gt; if you want to try them side by side without installing anything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The honest framing
&lt;/h2&gt;

&lt;p&gt;I've shipped engineering docs with both. Every six months someone on the team asks "should we standardise on Mermaid or PlantUML?" and every six months the answer is "it depends on where the diagram lives."&lt;/p&gt;

&lt;p&gt;That answer used to be a cop-out. In 2026 it's the truth. The two formats have converged on the same problem — render diagrams from plain text — and diverged on everything around it: who writes them, where they render, what they look like, and how much patience they expect from you.&lt;/p&gt;

&lt;p&gt;This article is the side-by-side I wish someone had handed me three years ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  At a glance
&lt;/h2&gt;

&lt;p&gt;The table you came here for:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Mermaid&lt;/th&gt;
&lt;th&gt;PlantUML&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Native rendering on GitHub&lt;/td&gt;
&lt;td&gt;✅ since 2022&lt;/td&gt;
&lt;td&gt;❌ (proxied images only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native rendering on Notion&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native rendering on GitLab&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IDE / editor extensions&lt;/td&gt;
&lt;td&gt;Broad (VS Code, JetBrains, Obsidian)&lt;/td&gt;
&lt;td&gt;Broad, with deeper JetBrains roots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Layout engine&lt;/td&gt;
&lt;td&gt;Dagre (flowcharts), ELK opt-in&lt;/td&gt;
&lt;td&gt;Graphviz (&lt;code&gt;dot&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supported diagram types&lt;/td&gt;
&lt;td&gt;~16&lt;/td&gt;
&lt;td&gt;~20+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Syntax style&lt;/td&gt;
&lt;td&gt;Markdown-adjacent&lt;/td&gt;
&lt;td&gt;Annotation-heavy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server-side renderer&lt;/td&gt;
&lt;td&gt;Headless Chromium&lt;/td&gt;
&lt;td&gt;Java + Graphviz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best at&lt;/td&gt;
&lt;td&gt;Flowcharts, sequence, journey&lt;/td&gt;
&lt;td&gt;Class, component, deployment, ERD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worst at&lt;/td&gt;
&lt;td&gt;Dense ERDs, large class diagrams&lt;/td&gt;
&lt;td&gt;Anything that needs to live on GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rest of this post is the detail under each row.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round 1 — Syntax ergonomics
&lt;/h2&gt;

&lt;p&gt;The same flow, written two ways. Pick which one reads more naturally to you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mermaid:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
  A[Client] --&amp;gt; B{Token valid?}
  B --&amp;gt;|Yes| C[Fetch user]
  B --&amp;gt;|No| D[Redirect to login]
  C --&amp;gt; E[Return 200]
  D --&amp;gt; F[Return 302]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;PlantUML:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml
start
:Client;
if (Token valid?) then (yes)
  :Fetch user;
  :Return 200;
else (no)
  :Redirect to login;
  :Return 302;
endif
@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mermaid's syntax leans on &lt;strong&gt;nodes and edges as the primitive&lt;/strong&gt;. You say "A points to B with this label" and the layout follows. It reads like a constraint list.&lt;/p&gt;

&lt;p&gt;PlantUML's syntax leans on &lt;strong&gt;statements as the primitive&lt;/strong&gt;. You say "do this, then this, with this branch" and the layout follows. It reads like pseudocode.&lt;/p&gt;

&lt;p&gt;For people who think in flow ("first this happens, then this"), PlantUML's &lt;code&gt;start/if/endif&lt;/code&gt; is intuitive. For people who think in graphs ("these are the nodes, these are the edges"), Mermaid is the lower-friction path.&lt;/p&gt;

&lt;p&gt;There's no objectively-better here. Pick the one that matches how your team already whiteboards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8dc8emezazdfx4gbkm5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8dc8emezazdfx4gbkm5j.png" alt="Same auth flow rendered from Mermaid source" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Same auth flow, Mermaid source, rendered into a finished SVG.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn17ra5im0gkddqvfo8x4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn17ra5im0gkddqvfo8x4.png" alt="Same auth flow rendered from PlantUML source" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Same flow expressed in PlantUML — different syntax, same end shape.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Round 2 — Layout quality
&lt;/h2&gt;

&lt;p&gt;Layout is where the two diverge the most, and it's the thing nobody talks about until they've shipped a dozen diagrams and realised one of the formats keeps making nodes overlap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mermaid uses Dagre&lt;/strong&gt; by default. Dagre is a hierarchical layout algorithm — fast, deterministic, and great on flow charts with 5 to 30 nodes. Past that it starts producing the visual you've seen on a thousand READMEs: tall, narrow columns with edges crossing in ways no human would draw.&lt;/p&gt;

&lt;p&gt;Mermaid has an &lt;code&gt;elk&lt;/code&gt; opt-in (Eclipse Layout Kernel) that's much better at dense graphs. As of 2026 it's still flagged as experimental in most distributions, but it's stable enough to use in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PlantUML uses Graphviz&lt;/strong&gt; (the &lt;code&gt;dot&lt;/code&gt; engine), which has been the gold standard for hierarchical graph layout for 30 years. The output reflects that — PlantUML diagrams routinely look right out of the box, especially as the graph grows past 20 nodes.&lt;/p&gt;

&lt;p&gt;For a 6-node flow chart, both produce something readable. For a 60-node class diagram, PlantUML wins by a noticeable margin.&lt;/p&gt;

&lt;p&gt;The catch: Graphviz is a native binary. Running PlantUML in a CI job or a serverless function means shipping a Java + Graphviz runtime. Mermaid is JavaScript end-to-end, which is the trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round 3 — Supported diagram types
&lt;/h2&gt;

&lt;p&gt;Both cover the basics; PlantUML covers more obscure ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mermaid (2026, native pack):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flowchart&lt;/li&gt;
&lt;li&gt;Sequence diagram&lt;/li&gt;
&lt;li&gt;Class diagram&lt;/li&gt;
&lt;li&gt;State diagram&lt;/li&gt;
&lt;li&gt;ER diagram&lt;/li&gt;
&lt;li&gt;Gantt&lt;/li&gt;
&lt;li&gt;Pie&lt;/li&gt;
&lt;li&gt;User journey&lt;/li&gt;
&lt;li&gt;Quadrant chart&lt;/li&gt;
&lt;li&gt;XY chart&lt;/li&gt;
&lt;li&gt;Mindmap&lt;/li&gt;
&lt;li&gt;Timeline&lt;/li&gt;
&lt;li&gt;Sankey&lt;/li&gt;
&lt;li&gt;Block diagram&lt;/li&gt;
&lt;li&gt;Git graph&lt;/li&gt;
&lt;li&gt;C4 (experimental)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;PlantUML (mature set):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All of the above, plus:&lt;/li&gt;
&lt;li&gt;Component diagram&lt;/li&gt;
&lt;li&gt;Deployment diagram&lt;/li&gt;
&lt;li&gt;Activity diagram (legacy + beta)&lt;/li&gt;
&lt;li&gt;Use case&lt;/li&gt;
&lt;li&gt;Object diagram&lt;/li&gt;
&lt;li&gt;Network diagram (&lt;code&gt;nwdiag&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Wireframe (Salt UI mockup)&lt;/li&gt;
&lt;li&gt;Archimate&lt;/li&gt;
&lt;li&gt;BPMN-like activity flows&lt;/li&gt;
&lt;li&gt;Bytefield diagrams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're writing a software architecture doc that needs &lt;strong&gt;deployment diagrams or component diagrams&lt;/strong&gt; — the boxes-inside-boxes-with-interfaces pattern — PlantUML's coverage is meaningfully wider. Mermaid's &lt;code&gt;block&lt;/code&gt; diagram type covers a chunk of this, but it's not at parity.&lt;/p&gt;

&lt;p&gt;If you're writing a feature spec with &lt;strong&gt;flowcharts, sequence diagrams, and ER diagrams&lt;/strong&gt; — the 80% case for product engineering — both are fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round 4 — Where it renders without help
&lt;/h2&gt;

&lt;p&gt;This is the single biggest practical difference, and the reason the answer in 2026 is "it depends on where the diagram lives".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mermaid renders natively on:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub READMEs and markdown files (since 2022)&lt;/li&gt;
&lt;li&gt;GitLab&lt;/li&gt;
&lt;li&gt;Notion code blocks&lt;/li&gt;
&lt;li&gt;VS Code markdown preview&lt;/li&gt;
&lt;li&gt;Obsidian&lt;/li&gt;
&lt;li&gt;Bitbucket Cloud&lt;/li&gt;
&lt;li&gt;Most static site generators with a plugin (Docusaurus, VitePress, MkDocs Material, Astro)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;PlantUML renders natively on:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitLab (snippets + wiki)&lt;/li&gt;
&lt;li&gt;JetBrains IDEs (with the official plugin)&lt;/li&gt;
&lt;li&gt;Confluence (with a plugin)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everywhere else, PlantUML rendering means either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pre-rendering to SVG/PNG and committing the image, or&lt;/li&gt;
&lt;li&gt;Pointing at a public PlantUML server (&lt;code&gt;www.plantuml.com/plantuml/svg/&amp;lt;encoded&amp;gt;&lt;/code&gt;) and accepting that your diagram source is encoded into a third-party URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a GitHub README in 2026, Mermaid is the only format that renders inline without a build step. That's not a small thing — it's the entire reason Mermaid has more momentum.&lt;/p&gt;

&lt;p&gt;For an internal Confluence-driven engineering org, PlantUML's class / component / deployment coverage and Graphviz layout makes it the better default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round 5 — Ecosystem and tooling
&lt;/h2&gt;

&lt;p&gt;Both ecosystems are healthy. They optimise for different surfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mermaid:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintained by a foundation; weekly releases&lt;/li&gt;
&lt;li&gt;Live editor at &lt;code&gt;mermaid.live&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Official CLI: &lt;code&gt;@mermaid-js/mermaid-cli&lt;/code&gt; (uses Puppeteer under the hood)&lt;/li&gt;
&lt;li&gt;VS Code extension by the maintainers&lt;/li&gt;
&lt;li&gt;Obsidian native support&lt;/li&gt;
&lt;li&gt;AI tooling generates Mermaid by default — most LLMs output Mermaid when asked for a diagram in markdown&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;PlantUML:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintained primarily by Arnaud Roques and a small team; releases are slower but steady&lt;/li&gt;
&lt;li&gt;Live editor at &lt;code&gt;www.plantuml.com/plantuml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Official tool: &lt;code&gt;plantuml.jar&lt;/code&gt; (Java)&lt;/li&gt;
&lt;li&gt;JetBrains plugin is best-in-class for the JVM crowd&lt;/li&gt;
&lt;li&gt;Confluence integration is a paid plugin but widely deployed&lt;/li&gt;
&lt;li&gt;AI tooling support is improving but still trails Mermaid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's a quieter consequence here. When you ask an LLM for "a diagram of X", you almost always get Mermaid back. That's mostly habit and training-set bias, not a quality call — but it does mean that if your team is leaning on AI-assisted doc writing, Mermaid will show up in your repo whether you picked it or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round 6 — Learning curve
&lt;/h2&gt;

&lt;p&gt;The bottom 20% of each language takes about an hour. The remaining 80% is what differs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mermaid&lt;/strong&gt; has a flat learning curve — the syntax is markdown-adjacent and most people write a working flowchart on their first try. The wall comes when you want to customise — &lt;code&gt;themeVariables&lt;/code&gt;, &lt;code&gt;init&lt;/code&gt; directives, &lt;code&gt;classDef&lt;/code&gt;, link styling — because each diagram type has its own subset of the customisation surface, and the documentation is scattered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PlantUML&lt;/strong&gt; has a steeper start — &lt;code&gt;@startuml&lt;/code&gt; / &lt;code&gt;@enduml&lt;/code&gt;, statement-based syntax, &lt;code&gt;skinparam&lt;/code&gt; overrides — but a flatter middle, because once you've learned &lt;code&gt;skinparam&lt;/code&gt; you've learned the customisation surface for every diagram type. The wall comes later, around legacy syntax (the original &lt;code&gt;activity&lt;/code&gt; grammar vs the newer &lt;code&gt;start/stop&lt;/code&gt; beta).&lt;/p&gt;

&lt;p&gt;For a team that ships occasional diagrams, Mermaid's flat start wins. For a team where someone "owns" the diagram system and is going to push it to its limits, PlantUML's consistency wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision rule
&lt;/h2&gt;

&lt;p&gt;Three questions, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Does the diagram need to render on GitHub or in a markdown file consumed by tools you don't control?&lt;/strong&gt; → Mermaid. Stop here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does it need to be a deployment, component, or detailed class diagram with 30+ nodes?&lt;/strong&gt; → PlantUML. Stop here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anything else?&lt;/strong&gt; → Mermaid for the lower install footprint and broader AI tooling; PlantUML if your team is already on JetBrains + Confluence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqjikzly4163zgz8tzd7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqjikzly4163zgz8tzd7.png" alt="Decision rule visualised as a three-question flow" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The 60-second decision rule.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most engineering teams in 2026 end up using &lt;strong&gt;Mermaid for repo-level docs and PlantUML for architecture documents that live in Confluence or a wiki.&lt;/strong&gt; That's not a compromise — it's the right answer. The cost of standardising on one format and forcing the wrong fit is higher than the cost of two file extensions in your repo.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Both formats, one editor: Don't pick — render both&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.beauty-diagram.com" rel="noopener noreferrer"&gt;Beauty Diagram&lt;/a&gt; parses Mermaid, PlantUML, and draw.io. Paste either format, pick from 9 production themes, export SVG or PNG. Useful when your docs repo has both formats and you want them to look consistent. &lt;em&gt;(Disclosure: I work on it.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;→ Try the editor&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The web flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Paste&lt;/strong&gt; the source — Mermaid or PlantUML — into the editor at &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;/editor&lt;/a&gt;. The format is auto-detected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick a theme&lt;/strong&gt;. The same nine themes (&lt;code&gt;classic&lt;/code&gt;, &lt;code&gt;modern&lt;/code&gt;, &lt;code&gt;atlas&lt;/code&gt;, &lt;code&gt;blueprint&lt;/code&gt;, &lt;code&gt;memphis&lt;/code&gt;, &lt;code&gt;obsidian&lt;/code&gt;, &lt;code&gt;slate&lt;/code&gt;, &lt;code&gt;brutalist&lt;/code&gt;, &lt;code&gt;atelier&lt;/code&gt;) apply to both formats, so a doc with a mix of Mermaid and PlantUML diagrams renders consistently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export&lt;/strong&gt; SVG or PNG, or use &lt;strong&gt;Share&lt;/strong&gt; to get a hot-linkable URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're scripting this from CI — say, beautifying every diagram in your docs repo on each release — the same pipeline runs from a CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Works on both Mermaid and PlantUML files&lt;/span&gt;
npx @beauty-diagram/cli beautify auth.mmd &lt;span class="nt"&gt;--theme&lt;/span&gt; atlas &lt;span class="nt"&gt;--out&lt;/span&gt; auth.svg
npx @beauty-diagram/cli beautify components.puml &lt;span class="nt"&gt;--theme&lt;/span&gt; atlas &lt;span class="nt"&gt;--out&lt;/span&gt; components.svg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bd themes&lt;/code&gt; lists the available themes. There's no per-property style override — the theme is the choice; you pick a different one if you don't like what you see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;The 60-second version:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mermaid wins&lt;/strong&gt; if the diagram lives in a README, a markdown file, a Notion page, or anything you don't fully control. It also wins if you're heavy on AI-assisted doc writing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PlantUML wins&lt;/strong&gt; if the diagram is a deployment / component / detailed class diagram, or if your team is centred on JetBrains + Confluence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Both is fine.&lt;/strong&gt; Pick the format per-diagram, not per-org.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this was useful, drop a ❤️ and follow — I'm posting weekly on diagrams, docs, and developer ergonomics. Next week: &lt;strong&gt;Generate Mermaid from plain English with AI — a CLI walkthrough&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Which one is your team standardised on, and did the decision survive the second year? Drop a note in the comments — I'm collecting the regret-or-validation stories.&lt;/p&gt;

</description>
      <category>mermaid</category>
      <category>plantuml</category>
      <category>opensource</category>
      <category>documentation</category>
    </item>
    <item>
      <title>Embed Mermaid in Notion: The 4 Working Approaches in 2026</title>
      <dc:creator>Levi Liu</dc:creator>
      <pubDate>Tue, 26 May 2026 10:38:23 +0000</pubDate>
      <link>https://dev.to/levi_liu/embed-mermaid-in-notion-the-4-working-approaches-in-2026-257f</link>
      <guid>https://dev.to/levi_liu/embed-mermaid-in-notion-the-4-working-approaches-in-2026-257f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;
Notion has native Mermaid in code blocks now, but the default look is the same pastel render you've seen everywhere, and there's no theme override. This post walks through the four approaches that actually work in 2026 — native code block, static image upload, public hot-linkable image, and live-updating embed — with a comparison table at the end so you can pick by trade-off. There's a &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;shortcut&lt;/a&gt; at the 70% mark if you'd rather skip the maintenance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why this article exists
&lt;/h2&gt;

&lt;p&gt;Two years ago, "embed Mermaid in Notion" was a search query that returned twenty Stack Overflow threads and zero working answers. Then Notion shipped native &lt;code&gt;mermaid&lt;/code&gt; code-block rendering, and the question went quiet.&lt;/p&gt;

&lt;p&gt;But the question didn't go away — it shifted. The native renderer works, but it gives you exactly one look: Mermaid's default theme, no overrides, no &lt;code&gt;themeVariables&lt;/code&gt; honored. The moment you want your team's Notion docs to feel like a finished product instead of a hackathon scratchpad, you're back to needing a workaround.&lt;/p&gt;

&lt;p&gt;There are four of them. Each makes a different trade between live-updating, aesthetic control, and how much pipeline you're willing to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four approaches at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Live updates&lt;/th&gt;
&lt;th&gt;Theme control&lt;/th&gt;
&lt;th&gt;Maintenance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Native &lt;code&gt;mermaid&lt;/code&gt; code block&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Static image upload&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Manual re-upload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Public hot-linkable image&lt;/td&gt;
&lt;td&gt;✅*&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Host the image&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Live embed via &lt;code&gt;/embed&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Host the endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* Live updates only if the source URL serves a fresh render each time.&lt;/p&gt;

&lt;p&gt;The rest of this post is just the details under each row.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 1: Native &lt;code&gt;mermaid&lt;/code&gt; code block
&lt;/h2&gt;

&lt;p&gt;The cheapest path. Type &lt;code&gt;/code&lt;/code&gt;, set the language to &lt;strong&gt;Mermaid&lt;/strong&gt;, paste your source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
  A[Client] --&amp;gt; B{Auth?}
  B --&amp;gt;|Yes| C[API]
  B --&amp;gt;|No| D[Login]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notion renders it live. You can edit the source, the diagram re-renders. Free, zero pipeline.&lt;/p&gt;

&lt;p&gt;What you give up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No theme override.&lt;/strong&gt; The &lt;code&gt;%%{init: {...}}%%&lt;/code&gt; directive is silently stripped in Notion's renderer. You get default Mermaid pastels whether you want them or not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; for dark mode.&lt;/strong&gt; Notion's dark/light switch doesn't tell Mermaid anything; the diagram stays one fixed palette.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No PDF export fidelity.&lt;/strong&gt; When you export the Notion page to PDF, the Mermaid block renders as a raster snapshot, often at a lower resolution than the page expects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use this for: internal scratch docs, RFCs, anything where "the diagram exists" is the bar.&lt;/p&gt;

&lt;p&gt;Don't use this for: public-facing docs, customer-shared Notion pages, anything you'd want to look intentional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 2: Static image upload
&lt;/h2&gt;

&lt;p&gt;Render the diagram to SVG or PNG offline, then drag the file into Notion. It becomes an Image block; Notion hosts it on its own CDN.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Official Mermaid CLI&lt;/span&gt;
npx @mermaid-js/mermaid-cli &lt;span class="nt"&gt;-i&lt;/span&gt; flow.mmd &lt;span class="nt"&gt;-o&lt;/span&gt; flow.svg &lt;span class="nt"&gt;-t&lt;/span&gt; base
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drag &lt;code&gt;flow.svg&lt;/code&gt; into the Notion page. Done.&lt;/p&gt;

&lt;p&gt;Pros: full theme control (you're rendering it yourself), works in PDF export, looks identical light and dark.&lt;/p&gt;

&lt;p&gt;Cons: &lt;strong&gt;no live updates.&lt;/strong&gt; Edit the Mermaid source, you re-render the file, you re-upload it. For a doc with five diagrams that change quarterly, this is fine. For a system architecture page that drifts weekly, it's a paper cut.&lt;/p&gt;

&lt;p&gt;A subtle gotcha: Notion &lt;strong&gt;strips SVG &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags and external font references&lt;/strong&gt; on upload. If your SVG depends on a webfont link in &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt;, the text falls back to Notion's default font. Inline the font with &lt;code&gt;font-family: -apple-system, system-ui, sans-serif&lt;/code&gt; to avoid the mismatch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 3: Public hot-linkable image
&lt;/h2&gt;

&lt;p&gt;Host the SVG somewhere public, then in Notion: &lt;code&gt;/image&lt;/code&gt; → &lt;strong&gt;Embed link&lt;/strong&gt; → paste the URL. Notion fetches it on every page load.&lt;/p&gt;

&lt;p&gt;This is the sweet spot for repos that already commit their diagrams as SVG. The pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Render the diagram into your repo: &lt;code&gt;diagrams/auth-flow.svg&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Commit and push.&lt;/li&gt;
&lt;li&gt;In Notion, embed: &lt;code&gt;https://github.com/&amp;lt;org&amp;gt;/&amp;lt;repo&amp;gt;/raw/main/diagrams/auth-flow.svg&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notion will fetch the URL each time the page loads. Push a new SVG to &lt;code&gt;main&lt;/code&gt;, the embed updates within a few minutes (GitHub's raw CDN has a short TTL).&lt;/p&gt;

&lt;p&gt;The catch: GitHub's &lt;code&gt;raw.githubusercontent.com&lt;/code&gt; serves with &lt;code&gt;Content-Type: text/plain&lt;/code&gt;, which some browsers refuse to render as an image. The reliable trick is to route through &lt;code&gt;https://github.com/&amp;lt;org&amp;gt;/&amp;lt;repo&amp;gt;/raw/main/...&lt;/code&gt; (no &lt;code&gt;raw.&lt;/code&gt; prefix), which redirects to a properly typed CDN response. Notion handles this redirect correctly.&lt;/p&gt;

&lt;p&gt;Other hosts work too — Cloudflare R2, S3 with a public bucket, any static CDN. The constraint is just: serve &lt;code&gt;image/svg+xml&lt;/code&gt;, allow Notion's user-agent, and don't gate behind auth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 4: Live embed via &lt;code&gt;/embed&lt;/code&gt; + hosted SVG endpoint
&lt;/h2&gt;

&lt;p&gt;The most flexible — and the most pipeline. Use Notion's &lt;code&gt;/embed&lt;/code&gt; block (which accepts any URL) to point at an endpoint that renders the Mermaid source on demand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/embed → https://your-domain.com/render?source=&amp;lt;encoded-mermaid&amp;gt;&amp;amp;theme=atlas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The endpoint does what Mermaid CLI does, but server-side, and returns &lt;code&gt;image/svg+xml&lt;/code&gt;. You can pass theme parameters in the query string, regenerate on every request, and the diagram in Notion always reflects whatever the endpoint serves right now.&lt;/p&gt;

&lt;p&gt;A barebones version in 50 lines of Node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mermaid-js/mermaid-cli&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs/promises&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/render&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tmpIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`/tmp/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;.mmd`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tmpOut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tmpIn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.mmd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tmpOut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;puppeteerConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--no-sandbox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tmpOut&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/svg+xml&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the "I want full control" path. You're now running a renderer. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A box (Lambda, Cloud Run, a Fly machine) running Chromium for Puppeteer&lt;/li&gt;
&lt;li&gt;A cache layer so identical sources don't re-render on every Notion poll&lt;/li&gt;
&lt;li&gt;A timeout policy so a malformed source doesn't hang&lt;/li&gt;
&lt;li&gt;Some auth or rate limiting so the endpoint doesn't become someone else's free render farm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a team that already has infra, the 80% solution above is a weekend project. For a solo dev, it's the moment you ask whether the time is worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When DIY stops being worth it
&lt;/h2&gt;

&lt;p&gt;Three signals it's time to stop hand-rolling the Notion pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You have more than ~10 diagrams across your Notion workspace and you're losing track of which ones are stale.&lt;/li&gt;
&lt;li&gt;You want a theme that matches your company's docs site, not Mermaid's defaults.&lt;/li&gt;
&lt;li&gt;The team's non-engineers want to make and edit diagrams without learning Mermaid or your render endpoint.&lt;/li&gt;
&lt;/ol&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The shortcut: Paste, pick a theme, embed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.beauty-diagram.com" rel="noopener noreferrer"&gt;Beauty Diagram&lt;/a&gt; is a web editor for Mermaid, PlantUML, and draw.io. Paste your source, pick from 9 production themes, get a hot-linkable URL that updates when you edit. Drop the URL into Notion's &lt;code&gt;/embed&lt;/code&gt; block and it stays live. &lt;em&gt;(Disclosure: I work on it.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;→ Try the editor&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The web flow for Notion specifically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Paste&lt;/strong&gt; your Mermaid source into the &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;editor&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick a theme&lt;/strong&gt; from nine: &lt;code&gt;classic&lt;/code&gt;, &lt;code&gt;modern&lt;/code&gt;, &lt;code&gt;atlas&lt;/code&gt;, &lt;code&gt;blueprint&lt;/code&gt;, &lt;code&gt;memphis&lt;/code&gt;, &lt;code&gt;obsidian&lt;/code&gt;, &lt;code&gt;slate&lt;/code&gt;, &lt;code&gt;brutalist&lt;/code&gt;, &lt;code&gt;atelier&lt;/code&gt;. Each is a complete design language — palette, typography, edge style, node treatment — tuned so the embed reads as a finished asset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save &amp;amp; Share&lt;/strong&gt; — generates a public URL with a 12-char token.&lt;/li&gt;
&lt;li&gt;In Notion, &lt;code&gt;/embed&lt;/code&gt; and paste the share URL's &lt;code&gt;.svg&lt;/code&gt; form, e.g. &lt;code&gt;https://api.beauty-diagram.com/v1/share/&amp;lt;token&amp;gt;.svg&lt;/code&gt;. The embed re-fetches on each page load; if you edit the share, Notion shows the new version within ~5 minutes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you'd rather automate from a CLI — say, a CI job that regenerates every diagram in your repo on each release — the same render pipeline is one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Render and get a hot-linkable URL in one shot&lt;/span&gt;
npx @beauty-diagram/cli embed-url flow.mmd &lt;span class="nt"&gt;--theme&lt;/span&gt; atlas &lt;span class="nt"&gt;--share&lt;/span&gt;
&lt;span class="c"&gt;# → https://api.beauty-diagram.com/v1/share/&amp;lt;token&amp;gt;.svg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bd embed-url --share&lt;/code&gt; saves the diagram first, then prints the share-resource SVG URL. Drop that URL directly into a Notion &lt;code&gt;/embed&lt;/code&gt; block, or any other surface that accepts an image URL. Re-running on the same file replaces the share contents in place, so the URL is stable and the embed picks up the update automatically.&lt;/p&gt;

&lt;p&gt;The CLI exposes the same nine themes (&lt;code&gt;bd themes&lt;/code&gt; lists them). It does not expose per-property style overrides — the philosophy is that the theme is the choice; you don't tune a theme, you pick a different one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking the right approach for your page
&lt;/h2&gt;

&lt;p&gt;A rough decision tree:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Throwaway internal doc?&lt;/strong&gt; Native code block. Five seconds, zero pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quarterly architecture review that gets exported to PDF?&lt;/strong&gt; Static SVG upload. Manual, but PDF-safe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagrams that already live in your repo?&lt;/strong&gt; GitHub raw URL embed via &lt;code&gt;/image&lt;/code&gt;. Free, auto-updates on push.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer-facing Notion page, or a team doc that drifts weekly?&lt;/strong&gt; Live embed against a hosted endpoint. Either roll your own, or use a service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trap to avoid: picking the most powerful approach for every diagram. Native code blocks are fine when "the diagram exists" is the bar — don't over-engineer them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;The four approaches, recapped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native &lt;code&gt;mermaid&lt;/code&gt; code block&lt;/strong&gt; — free, live, but locked to Mermaid defaults.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static image upload&lt;/strong&gt; — full control, but no live updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public hot-linkable image&lt;/strong&gt; — live and themed, but you host the SVG.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live embed via &lt;code&gt;/embed&lt;/code&gt;&lt;/strong&gt; — full pipeline, full control, the most work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this was useful, drop a ❤️ and follow — I'm posting weekly on diagrams, docs, and developer ergonomics. Next week: &lt;strong&gt;Mermaid vs PlantUML in 2026 — which to pick for engineering docs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What's your team's Notion diagram setup — native blocks, static uploads, or something else? Drop a note in the comments; I'm collecting setups for a follow-up.&lt;/p&gt;

</description>
      <category>mermaid</category>
      <category>notion</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why Your GitHub README Diagrams Look Amateur (and the 4 Fixes That Take 10 Minutes)</title>
      <dc:creator>Levi Liu</dc:creator>
      <pubDate>Wed, 20 May 2026 10:41:08 +0000</pubDate>
      <link>https://dev.to/levi_liu/why-your-github-readme-diagrams-look-amateur-and-the-4-fixes-that-take-10-minutes-4a9c</link>
      <guid>https://dev.to/levi_liu/why-your-github-readme-diagrams-look-amateur-and-the-4-fixes-that-take-10-minutes-4a9c</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;
If your README diagrams look like every other open-source repo's, that's because they all use the same four defaults. Switching to &lt;code&gt;theme: 'base'&lt;/code&gt; plus tuning four properties takes under ten minutes and produces a diagram that looks intentional. This is a follow-up to last week's &lt;a href="https://www.beauty-diagram.com/blog/render-mermaid-as-svg" rel="noopener noreferrer"&gt;SVG rendering deep-dive&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The four defaults that ruin your diagrams
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pastel pink/blue palette&lt;/strong&gt; — the &lt;code&gt;default&lt;/code&gt; theme is from a 2014 Bootstrap-era moodboard. It signals "I copy-pasted from the docs."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Curved edges (&lt;code&gt;basis&lt;/code&gt;)&lt;/strong&gt; — works for organic flows, terrible for technical diagrams. Lines that should be crisp end up wavy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default font&lt;/strong&gt; — varies wildly by viewer. Looks fine in the GitHub editor preview, looks like Times New Roman in your CI artifact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardcoded background&lt;/strong&gt; — light theme on a dark page, or vice versa. The diagram becomes a rectangle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each takes one config change to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 1: Switch to base theme
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%%{init: {'theme':'base'}}%%
flowchart LR
  A --&amp;gt; B --&amp;gt; C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;base&lt;/code&gt; is the only theme that exposes &lt;code&gt;themeVariables&lt;/code&gt; for full control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 2: Set six theme variables
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;%%&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;init:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;'theme':'base'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;'themeVariables':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;'primaryColor':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'#&lt;/span&gt;&lt;span class="mi"&gt;1e293&lt;/span&gt;&lt;span class="err"&gt;b'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;'primaryTextColor':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'#f&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;fafc'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;'primaryBorderColor':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'#&lt;/span&gt;&lt;span class="mi"&gt;475569&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;'lineColor':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'#&lt;/span&gt;&lt;span class="mi"&gt;94&lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;b&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;'fontFamily':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'system-ui&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sans-serif'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;'fontSize':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="err"&gt;px'&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;%%&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six variables. That's the entire customization surface you actually need. Mermaid exposes around fifty in total, but the ones above cover 90% of the visual identity of a diagram. Ignore the rest unless you have a specific reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 3: Linear edges
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;%%&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;init:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;'flowchart':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;'curve':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'linear'&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;&lt;span class="err"&gt;%%&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For hierarchies, use &lt;code&gt;step&lt;/code&gt;. For organic flows, keep &lt;code&gt;basis&lt;/code&gt;. For everything else, &lt;code&gt;linear&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 4: Light/dark adaptive embed
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"(prefers-color-scheme: dark)"&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"./diagrams/auth-flow-dark.svg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Auth flow"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./diagrams/auth-flow-light.svg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub READMEs respect &lt;code&gt;prefers-color-scheme&lt;/code&gt;. Ship two SVGs and let GitHub pick.&lt;/p&gt;

&lt;p&gt;A small but important caveat: this only works for &lt;strong&gt;pre-rendered SVGs&lt;/strong&gt; that you commit to the repo. Inline &lt;code&gt;mermaid&lt;/code&gt; code blocks in your README can't use &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; — they're rendered by GitHub's own Mermaid runtime at view time, with no hook for swapping based on theme. If you want adaptive diagrams in a README, you have to render to SVG first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting all four together
&lt;/h2&gt;

&lt;p&gt;Here's the minimum viable beautified README diagram, end to end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
config:
  theme: base
  themeVariables:
    primaryColor: '#1e293b'
    primaryTextColor: '#f8fafc'
    primaryBorderColor: '#475569'
    lineColor: '#94a3b8'
    fontFamily: 'system-ui, sans-serif'
    fontSize: '14px'
  flowchart:
    curve: linear
---
flowchart LR
  A[Client] --&amp;gt; B{Auth?}
  B --&amp;gt;|Yes| C[API]
  B --&amp;gt;|No| D[Login]
  C --&amp;gt; E[(Database)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontmatter form (&lt;code&gt;---\nconfig:\n  ...&lt;/code&gt;) is Mermaid v11's preferred syntax. The older &lt;code&gt;%%{init: {...}}%%&lt;/code&gt; directive still works and is what you'll see in most blog posts — pick whichever your renderer is happy with.&lt;/p&gt;

&lt;h2&gt;
  
  
  When DIY stops being worth the time
&lt;/h2&gt;

&lt;p&gt;Everything above works. I've shipped this exact pipeline.&lt;/p&gt;

&lt;p&gt;But the moment you have more than a handful of diagrams, or you want a different look for slides vs. docs vs. PRs, you're maintaining a config file. And every new contributor to the repo needs to know about it. That's where I personally tap out.&lt;/p&gt;

&lt;p&gt;Three signals it's time to graduate from hand-tuned themes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You're copy-pasting the same &lt;code&gt;themeVariables&lt;/code&gt; block across multiple repos.&lt;/li&gt;
&lt;li&gt;You want a different look for a slide deck than for the README, but the diagram source stays the same.&lt;/li&gt;
&lt;li&gt;Someone non-technical on the team needs to make a diagram and you don't want to teach them YAML frontmatter.&lt;/li&gt;
&lt;/ol&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The shortcut: Paste, pick a theme, export&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.beauty-diagram.com" rel="noopener noreferrer"&gt;Beauty Diagram&lt;/a&gt; is a web editor for Mermaid, PlantUML, and draw.io. Paste your source, pick from 9 production themes, export SVG or PNG. No &lt;code&gt;themeVariables&lt;/code&gt; to maintain. &lt;em&gt;(Disclosure: I work on it.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;→ Open the editor&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The fastest path is the &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;web editor&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Paste&lt;/strong&gt; your Mermaid source on the left.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick a theme&lt;/strong&gt; from nine: &lt;code&gt;classic&lt;/code&gt;, &lt;code&gt;modern&lt;/code&gt;, &lt;code&gt;atlas&lt;/code&gt;, &lt;code&gt;blueprint&lt;/code&gt;, &lt;code&gt;memphis&lt;/code&gt;, &lt;code&gt;obsidian&lt;/code&gt;, &lt;code&gt;slate&lt;/code&gt;, &lt;code&gt;brutalist&lt;/code&gt;, &lt;code&gt;atelier&lt;/code&gt;. Each one is a complete design language — palette, typography, edge style, node treatment — not just a colour swap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export&lt;/strong&gt; SVG (vector for repos) or PNG (&lt;code&gt;standard&lt;/code&gt; / &lt;code&gt;high&lt;/code&gt; / &lt;code&gt;max&lt;/code&gt; quality for slides).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share&lt;/strong&gt; to get a public hot-linkable URL that updates when the source is edited — drop it into Notion or Linear without re-uploading.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The same renderer is also a CLI if you'd rather automate the README pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Render once, ship to your repo&lt;/span&gt;
npx @beauty-diagram/cli beautify flow.mmd &lt;span class="nt"&gt;--theme&lt;/span&gt; modern &lt;span class="nt"&gt;--out&lt;/span&gt; flow.svg

&lt;span class="c"&gt;# Or render light + dark in one go for the &amp;lt;picture&amp;gt; embed&lt;/span&gt;
npx @beauty-diagram/cli beautify flow.mmd &lt;span class="nt"&gt;--theme&lt;/span&gt; modern   &lt;span class="nt"&gt;--out&lt;/span&gt; flow-light.svg
npx @beauty-diagram/cli beautify flow.mmd &lt;span class="nt"&gt;--theme&lt;/span&gt; obsidian &lt;span class="nt"&gt;--out&lt;/span&gt; flow-dark.svg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI exposes the same nine themes (&lt;code&gt;bd themes&lt;/code&gt; lists them). It does not expose per-variable overrides — the philosophy is that the theme is the choice; you don't tune a theme, you pick a different one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;The README-diagram embarrassment problem is fixable in ten minutes. The four fixes, recapped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;theme: 'base'&lt;/code&gt; — only theme that accepts overrides.&lt;/li&gt;
&lt;li&gt;Six &lt;code&gt;themeVariables&lt;/code&gt; — &lt;code&gt;primaryColor&lt;/code&gt;, &lt;code&gt;primaryTextColor&lt;/code&gt;, &lt;code&gt;primaryBorderColor&lt;/code&gt;, &lt;code&gt;lineColor&lt;/code&gt;, &lt;code&gt;fontFamily&lt;/code&gt;, &lt;code&gt;fontSize&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flowchart.curve: linear&lt;/code&gt; — sharp edges for technical diagrams.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; + &lt;code&gt;prefers-color-scheme&lt;/code&gt; — adaptive light/dark, GitHub-native.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most repos haven't done it because nobody told them where to look. Now you know.&lt;/p&gt;

&lt;p&gt;If this was useful, drop a ❤️ and follow — I'm posting weekly on diagrams, docs, and developer ergonomics. Next week: &lt;strong&gt;how to embed Mermaid diagrams in Notion (the four working approaches in 2026)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What's the worst-looking diagram in a README you've actually opened a PR against? Drop a link in the comments — I'm collecting examples for a future post.&lt;/p&gt;

</description>
      <category>mermaid</category>
      <category>github</category>
      <category>opinion</category>
      <category>documentation</category>
    </item>
    <item>
      <title>How to Render Mermaid Diagrams as SVG (and Stop Looking Like Every Other README)</title>
      <dc:creator>Levi Liu</dc:creator>
      <pubDate>Sun, 10 May 2026 22:00:00 +0000</pubDate>
      <link>https://dev.to/levi_liu/how-to-render-mermaid-diagrams-as-svg-and-stop-looking-like-every-other-readme-1e10</link>
      <guid>https://dev.to/levi_liu/how-to-render-mermaid-diagrams-as-svg-and-stop-looking-like-every-other-readme-1e10</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;
Mermaid renders to SVG natively — but the default output usually isn't what you want in a README, slide, or doc. This post walks through the official &lt;code&gt;mmdc&lt;/code&gt; CLI, the four theming knobs that actually matter, the three rendering pitfalls everyone hits (fonts, viewBox, dark mode), and the fastest path when you don't want to fight with config. There's a &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;live editor&lt;/a&gt; at the end if you want to skip ahead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The problem nobody talks about
&lt;/h2&gt;

&lt;p&gt;Mermaid is the de-facto "diagrams as code" choice in 2026 — GitHub, Notion, Obsidian, Docusaurus, GitLab, every static site generator worth its salt renders it natively.&lt;/p&gt;

&lt;p&gt;That's the good news.&lt;/p&gt;

&lt;p&gt;The bad news: 95% of Mermaid diagrams in the wild look exactly the same. Pastel pinks and blues, Comic-Sans-adjacent fonts, edges crossing nodes, arrowheads that don't quite point at anything. You've seen them. You've probably shipped some.&lt;/p&gt;

&lt;p&gt;It's not a Mermaid problem — it's a defaults problem. The renderer is optimized for "something showed up", not "this is presentable".&lt;/p&gt;

&lt;h2&gt;
  
  
  Why SVG and not PNG
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;SVG&lt;/th&gt;
&lt;th&gt;PNG&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scales without blur&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accessible (text selectable)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adapts to dark mode (&lt;code&gt;currentColor&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Searchable in your repo&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Approach 1: The official Mermaid CLI
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run without installing&lt;/span&gt;
npx @mermaid-js/mermaid-cli &lt;span class="nt"&gt;-i&lt;/span&gt; diagram.mmd &lt;span class="nt"&gt;-o&lt;/span&gt; diagram.svg

&lt;span class="c"&gt;# Or install globally&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @mermaid-js/mermaid-cli
mmdc &lt;span class="nt"&gt;-i&lt;/span&gt; diagram.mmd &lt;span class="nt"&gt;-o&lt;/span&gt; diagram.svg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The four theming knobs that actually matter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;theme&lt;/code&gt; (the cheapest win)
&lt;/h3&gt;

&lt;p&gt;Built-in Mermaid themes: &lt;code&gt;default&lt;/code&gt;, &lt;code&gt;forest&lt;/code&gt;, &lt;code&gt;dark&lt;/code&gt;, &lt;code&gt;neutral&lt;/code&gt;, &lt;code&gt;base&lt;/code&gt;. Pick &lt;code&gt;base&lt;/code&gt; if you want to customize from scratch.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;themeVariables&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Six variables actually matter: &lt;code&gt;primaryColor&lt;/code&gt;, &lt;code&gt;primaryTextColor&lt;/code&gt;, &lt;code&gt;primaryBorderColor&lt;/code&gt;, &lt;code&gt;lineColor&lt;/code&gt;, &lt;code&gt;fontFamily&lt;/code&gt;, &lt;code&gt;fontSize&lt;/code&gt;. Set those well, ignore the other 50.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Edge curves
&lt;/h3&gt;

&lt;p&gt;Change edge curves from the default to &lt;code&gt;linear&lt;/code&gt; or &lt;code&gt;step&lt;/code&gt;. The default &lt;code&gt;basis&lt;/code&gt; everywhere is one of the top reasons README diagrams look amateur.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Layout direction
&lt;/h3&gt;

&lt;p&gt;Pick based on reading flow. &lt;code&gt;LR&lt;/code&gt; for pipelines, &lt;code&gt;TD&lt;/code&gt; for hierarchies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three rendering pitfalls
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Fonts don't render in the saved SVG
&lt;/h3&gt;

&lt;p&gt;Use a system font stack: &lt;code&gt;-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  viewBox cropping
&lt;/h3&gt;

&lt;p&gt;Post-process to add padding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;padViewBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;svgString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;padding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;svgString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sr"&gt;/viewBox="&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;?\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.?\d&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;?\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.?\d&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.?\d&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.?\d&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;"/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ny&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;padding&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;padding&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`viewBox="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;nw&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;nh&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dark mode is hardcoded
&lt;/h3&gt;

&lt;p&gt;Replace fixed colors with &lt;code&gt;currentColor&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeAdaptive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;svgString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;svgString&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/stroke="#&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-9a-fA-F&lt;/span&gt;&lt;span class="se"&gt;]{6}&lt;/span&gt;&lt;span class="sr"&gt;"/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stroke="currentColor"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/fill="#&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-9a-fA-F&lt;/span&gt;&lt;span class="se"&gt;]{6}&lt;/span&gt;&lt;span class="sr"&gt;"/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fill="currentColor"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When DIY stops being worth the time
&lt;/h2&gt;

&lt;p&gt;Everything above works. I've shipped this exact pipeline.&lt;/p&gt;

&lt;p&gt;It also takes about a day of fiddling to get right, and the result is one diagram style that you maintain forever. The moment you want a different style for a different context — a slide deck vs. a README vs. a postmortem — or someone non-technical on the team wants to make a diagram, the cost-benefit shifts.&lt;/p&gt;

&lt;p&gt;Three signals it's time to stop hand-rolling:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You're maintaining a "diagram theme" file across multiple repos.&lt;/li&gt;
&lt;li&gt;You want a different look for slides vs. docs vs. PRs, but the diagram source stays the same.&lt;/li&gt;
&lt;li&gt;Your inputs aren't just Mermaid — PlantUML, draw.io, AI prompts.&lt;/li&gt;
&lt;/ol&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The shortcut: Paste, pick a theme, export&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.beauty-diagram.com" rel="noopener noreferrer"&gt;Beauty Diagram&lt;/a&gt; is a web editor for Mermaid, PlantUML, and draw.io. Paste your source, pick from 9 production themes, export SVG or PNG. No config files. &lt;em&gt;(Disclosure: I work on it.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;→ Open the editor&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The fastest path is the &lt;a href="https://www.beauty-diagram.com/editor" rel="noopener noreferrer"&gt;web editor&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Paste&lt;/strong&gt; your Mermaid source on the left.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick a theme&lt;/strong&gt; from nine: &lt;code&gt;classic&lt;/code&gt;, &lt;code&gt;modern&lt;/code&gt;, &lt;code&gt;atlas&lt;/code&gt;, &lt;code&gt;blueprint&lt;/code&gt;, &lt;code&gt;memphis&lt;/code&gt;, &lt;code&gt;obsidian&lt;/code&gt;, &lt;code&gt;slate&lt;/code&gt;, &lt;code&gt;brutalist&lt;/code&gt;, &lt;code&gt;atelier&lt;/code&gt;. Each is a complete design language — typography, palette, edge style, node treatment — tuned so the diagram reads as a finished asset, not a default render.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export&lt;/strong&gt; SVG (vector for docs / repos) or PNG (&lt;code&gt;standard&lt;/code&gt; / &lt;code&gt;high&lt;/code&gt; / &lt;code&gt;max&lt;/code&gt; quality for slides and social).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share&lt;/strong&gt; to get a public hot-linkable URL with an OG preview — drop it into Notion or Linear and it stays live as you edit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4zbvucn337gny32s27di.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4zbvucn337gny32s27di.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's the whole loop. No &lt;code&gt;themeVariables&lt;/code&gt; JSON to maintain. No post-processing scripts. The same renderer powers a CLI if you'd rather automate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Render once, ship to your repo&lt;/span&gt;
npx @beauty-diagram/cli beautify flow.mmd &lt;span class="nt"&gt;--theme&lt;/span&gt; modern &lt;span class="nt"&gt;--out&lt;/span&gt; flow.svg

&lt;span class="c"&gt;# Export at higher quality for slides&lt;/span&gt;
npx @beauty-diagram/cli &lt;span class="nb"&gt;export &lt;/span&gt;flow.mmd &lt;span class="nt"&gt;--theme&lt;/span&gt; atlas &lt;span class="nt"&gt;--format&lt;/span&gt; png &lt;span class="nt"&gt;--quality&lt;/span&gt; max &lt;span class="nt"&gt;--out&lt;/span&gt; flow.png

&lt;span class="c"&gt;# Get a public share URL (with OG preview baked in)&lt;/span&gt;
npx @beauty-diagram/cli share flow.mmd &lt;span class="nt"&gt;--theme&lt;/span&gt; modern &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"Auth flow"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI exposes the same nine themes (&lt;code&gt;bd themes&lt;/code&gt; lists them). It does not expose per-variable overrides — the philosophy is that the theme is the choice; you don't tune a theme, you pick a different one. For most readers this is a feature, not a limitation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;Mermaid's defaults aren't bad — they're designed for "the diagram exists" rather than "the diagram is finished". The fixes break down into roughly three tiers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cheap and fine for one style&lt;/strong&gt;: switch &lt;code&gt;theme: 'base'&lt;/code&gt;, set six theme variables, change edge curves, run a viewBox-padding regex.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Annoying past one repo&lt;/strong&gt;: maintain that config across many surfaces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a tool&lt;/strong&gt;: paste, pick, export.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where you land depends on how much you care about diagrams and how often you ship them.&lt;/p&gt;

&lt;p&gt;If this was useful, drop a ❤️ and follow — I'm posting weekly on diagrams, docs, and developer ergonomics. Next week: &lt;strong&gt;why your GitHub README diagrams look amateur, and the four fixes that take 10 minutes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What's the worst Mermaid diagram you've shipped? Drop a screenshot in the comments — I'll write up the most common issues in a follow-up.&lt;/p&gt;

</description>
      <category>mermaid</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
