All posts
·5 min read·By Elena Renderfy

Export Mermaid Diagrams as PNG or PDF Programmatically

The Mermaid CLI requires a headless browser anyway. Here's a simpler way to convert diagram syntax to portable images in your pipeline.

DiagramsMermaidTutorial

Mermaid is excellent for writing diagrams as text — flowcharts, sequence diagrams, ERDs, Gantt charts — especially when they live alongside code in a repository. But when you need to embed those diagrams in a PDF, an email, a Confluence page, or any system that doesn't render Mermaid natively, you need to export them as static images. This guide covers the real options.

Why exporting Mermaid diagrams is non-trivial

Mermaid is a JavaScript library designed to run in a browser. It takes diagram syntax, compiles it to SVG using its own layout engine, and renders it in the DOM. Exporting a static image from that output requires one of:

  • A real browser (headless Chromium) to run the JavaScript and capture the result
  • A server-side Mermaid integration that manages that browser process for you

There's no "pure Node.js, no browser" path that actually works well — attempts to use jsdom or canvas polyfills either fail outright or produce broken output because Mermaid's layout engine depends on real browser geometry APIs.

Option 1: Mermaid CLI (mmdc)

The official @mermaid-js/mermaid-cli package provides an mmdc command that accepts a .mmd file and outputs a PNG or SVG. Under the hood it runs Puppeteer, so it requires Chromium — but it hides the setup behind the CLI interface.

# Install
npm install -g @mermaid-js/mermaid-cli

# Convert
echo "flowchart TD
  A[Client] --> B(API)
  B --> C[Database]" > diagram.mmd

mmdc -i diagram.mmd -o diagram.png

This works well for local use and CI pipelines where you can install Chromium. The limitations are the same as running Puppeteer directly: binary size, system dependencies, difficulty in serverless environments.

Option 2: Mermaid.ink (public API, not for production)

mermaid.ink is a free public service that accepts base64-encoded Mermaid syntax in a URL and returns an image. It's useful for prototyping:

const encoded = Buffer.from(diagramSyntax).toString('base64');
const url = `https://mermaid.ink/img/${encoded}`;

Don't use this in production — it's a shared public service with no SLA, rate limits, or uptime guarantees. It also sends your diagram content to a third party.

Option 3: A render API with diagram support

Render APIs that support Mermaid natively handle the browser management on their end. You POST diagram syntax, get back a PNG or PDF — no CLI, no Puppeteer, no system dependencies.

const response = await fetch('https://renderfy.io/api/v1/render', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer rfy_live_YOUR_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    type: 'diagram',
    content: `
      flowchart TD
        A[Client] --> B(API Gateway)
        B --> C[Auth Service]
        B --> D[Render Service]
        D --> E[(Storage)]
    `,
    options: { format: 'png', dimensions: '1200x800' },
  }),
});

const png = Buffer.from(await response.arrayBuffer());

Flowchart shorthand (nodes without a flowchart TD header) is auto-prefixed, so minimal syntax works as-is.

Getting vector quality with PDF output

For documentation, slide decks, or any context where the diagram might be zoomed or printed, PNG rasters at any resolution will eventually look soft. Use format: "pdf" instead — the PDF path embeds the Mermaid-compiled SVG directly as vector data, which is resolution-independent and stays sharp at any size.

options: { format: 'pdf', dimensions: '1200x800' }

Building a diagram export pipeline

A common pattern is to run diagram export as part of a documentation build. For a docs pipeline that reads .mmd files from a /diagrams directory and exports them as PNGs:

import fs from 'fs';
import path from 'path';

const DIAGRAMS_DIR = './diagrams';
const OUTPUT_DIR = './public/diagrams';

fs.mkdirSync(OUTPUT_DIR, { recursive: true });

for (const file of fs.readdirSync(DIAGRAMS_DIR).filter(f => f.endsWith('.mmd'))) {
  const syntax = fs.readFileSync(path.join(DIAGRAMS_DIR, file), 'utf-8');

  const res = await fetch('https://renderfy.io/api/v1/render', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.RENDERFY_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      type: 'diagram',
      content: syntax,
      options: { format: 'png', dimensions: '1600x900' },
    }),
  });

  const outputPath = path.join(OUTPUT_DIR, file.replace('.mmd', '.png'));
  fs.writeFileSync(outputPath, Buffer.from(await res.arrayBuffer()));
  console.log(`Exported ${file} → ${outputPath}`);
}

Run this script as part of your build step and commit the output PNGs, or generate them on demand and serve from a CDN.


For occasional local exports, the Mermaid CLI is the simplest path. For anything that runs in a CI pipeline, a serverless function, or at scale, a render API removes the Chromium dependency from your deployment without sacrificing output quality.

Further reading

Try it yourself

100 free credits. No card needed. First render in under 5 minutes.

Get started free