Adding icons to Mermaid charts
This post is part of the Adding MermaidJS Without Any JS series.
Woodpecker CI, Hugo & MermaidJSAdding icons to Mermaid charts
While we are ricing…enhancing this blog with MermaidJS charts, we might as well add icons to said charts as well! This was also surprisingly easy to do, so here we go…

Not every article needs a picture
As of mermaid-cli version 11.10.1 one can add icon packs when rendering MermaidJS charts! It was implemented in PR954 which provides some details on how to use it, which essentially is just adding below to the mermaid-cli call:
--iconPacks '@iconify-json/logos' \
--iconPacksNamesAndUrls "azure#https://raw.githubusercontent.com/NakayamaKento/AzureIcons/refs/heads/main/icons.json"
…and then you can use icons!
architecture-beta
group api(azure:azure-cloud-shell)[API]
service db(azure:azure-database-postgresql-server)[Database] in api
service disk1(azure:azure-fileshares)[Storage] in api
service disk2(azure:data-box)[Storage] in api
service server(azure:app-services)[Server] in api
db:L -- R:server
disk1:T -- B:server
disk2:T -- B:db
Above will render like below:
Look at all the icons!
I haven’t found any preview of the icons in the repository I’m using in this example, so it’s always a surprise what comes out. :-) There is, however, an icon gallery at icones.js.org which does not contain this particular set, but many others.
This is my current publish.yaml workflow:
when:
- event: [push, manual]
branch: master
steps:
mermaidcharts:
image: ghcr.io/mermaid-js/mermaid-cli/mermaid-cli:11.12.0
commands:
- |
#!/bin/sh
set -o errexit # abort on nonzero exitstatus
set -o nounset # abort on unbound variable
set -o pipefail # don't hide errors within pipes
for md_file in $(grep -l -r mermaid content|grep -E "md$"); do
echo "Converting $md_file"
dir=$(dirname $md_file)
bas=$(basename $md_file)
cd $dir
/home/mermaidcli/node_modules/.bin/mmdc \
--puppeteerConfigFile /puppeteer-config.json \
-i $bas \
-o $bas \
--theme $THEME \
--backgroundColor $BACKGROUND \
--outputFormat $OUTPUT_FORMAT \
--iconPacks '@iconify-json/logos' \
--iconPacksNamesAndUrls "azure#https://raw.githubusercontent.com/NakayamaKento/AzureIcons/refs/heads/main/icons.json"
sed -i -E 's|!\[([^]]*)\]\(\./([^ ]+) "([^"]+)"\)|\{\{< figure src="\2" alt="\3" caption="\1" >\}\}|g;s|!\[([^]]*)\]\(\./([^)]*)\)|\{\{< figure src="\2" caption="\1" >\}\}|g' $bas
cd -
done
environment:
THEME: 'default'
BACKGROUND: 'transparent'
OUTPUT_FORMAT: 'svg'
build:
image: hugomods/hugo:go-git-0.150.1
depends_on:
- mermaidcharts
commands:
- hugo --minify
environment:
INTERNAL_URL:
from_secret: internal-url
HUGO_ENV: 'production'
compress:
image: alpine:latest
depends_on:
- build
commands:
- apk add -q --no-cache findutils brotli gzip zstd
- |
find ./public -type f -regex ".*\.\(css\|html\|js\|json\|svg\|xml\)$" \
-exec brotli -v --best {} \+ \
-exec gzip -v --best -k {} \+ \
-exec zstd -v -q {} \+
flyio:
image: alpine:latest
depends_on:
- compress
commands:
- apk add --no-cache -q curl
- curl -L https://fly.io/install.sh | sh
- /root/.fly/bin/flyctl deploy
environment:
FLY_ACCESS_TOKEN:
from_secret: flyio-access-token
FLY_APP:
from_secret: flyio-app-name
NO_COLOR: 1