Repository navigation
Markdown to PDF Speed Comparison 2026 10 12
RayoMD 4.0.0 against glu, Pandoc with Typst, md-to-pdf and Pandoc with XeLaTeX, converting the
repository's tester.md, each tool as a fresh process, start to exit. The tools render
different Markdown subsets, so this compares time to a finished PDF, not identical output.
- AMD Ryzen 5 PRO 4650GE (12 threads), Linux, a Debian 12 Docker container with
--network none, files on tmpfs. No CPU pinning: each tool used the cores it normally uses. - Median of 20 runs after one uncounted warm-up; output overwritten each run; every output checked to be a complete PDF.
-
scripts/compare_markdown_pdf_tools.py(tools/benchmark.py competitors), each command started in the document's folder.
| Tool | Version | Command |
|---|---|---|
| RayoMD | 4.0.0 (release rayomd-4.0.0-linux-x64) |
rayomd --export IN OUT native modern normal |
| glu | 0.0.43 (release glu-linux-amd64) |
glu -q -o OUT IN |
| Pandoc + Typst | Pandoc 3.12.1, Typst 0.15.1 | pandoc IN -o OUT --pdf-engine=typst … |
| md-to-pdf | 5.2.5, Node 22.23.3, Chromium 154 |
scripts/md_to_pdf_runner.cjs (A4, 20 mm margins) |
| Pandoc + XeLaTeX | Pandoc 3.12.1, TeX Live 2022 | pandoc IN -o OUT --pdf-engine=xelatex … |
Both Pandoc routes read -f markdown+tex_math_single_backslash-raw_tex (so \[ … \] is
display math, as in RayoMD, and a stray backslash in text is text) with DejaVu Sans and DejaVu
Sans Mono; md-to-pdf ran Chromium with --no-sandbox (inside the container).
tester.md (5,162 bytes) tests fallbacks on purpose: two remote images, a missing local image,
and a formula with an unknown TeX command. With those, glu stops with an error at the first
image it cannot open, XeLaTeX stops at the unknown command, and Pandoc waits on the network for
the remote images; RayoMD shows each as fallback text. So both measured documents leave them
out:
| Document | Bytes | SHA-256 (first 16) | Contents |
|---|---|---|---|
tester-local.md |
4,880 | 4833c4ff1c15fe54 |
tester.md without lines 71-72, 106, 108 and 110; keeps the 1024×1024 RGBA mascot PNG |
tester-noimg.md |
4,750 | 0d35d7a801d21274 |
also without every other line starting with an image and the [logo-ref] definition |
Without images:
| Tool | Median | Min | Max | vs RayoMD | PDF bytes | Formulas |
|---|---|---|---|---|---|---|
| RayoMD | 1.58 ms | 1.50 | 2.68 | 1× | 81,649 | typeset |
| glu | 55.75 ms | 53.74 | 57.48 | 35× | 55,516 | left as TeX source |
| Pandoc + Typst | 112.24 ms | 110.79 | 113.49 | 71× | 97,626 | typeset |
| md-to-pdf | 1,669.84 ms | 1,663.69 | 1,685.75 | 1,057× | 113,072 | left as TeX source |
| Pandoc + XeLaTeX | 1,708.19 ms | 1,695.76 | 1,716.33 | 1,081× | 61,773 | typeset |
With the PNG:
| Tool | Median | Min | Max | vs RayoMD | PDF bytes |
|---|---|---|---|---|---|
| RayoMD | 27.85 ms | 27.52 | 28.56 | 1× | 391,383 |
| glu | 86.47 ms | 84.31 | 88.41 | 3.1× | 347,399 |
| Pandoc + Typst | 148.45 ms | 146.97 | 149.95 | 5.3× | 370,198 |
| md-to-pdf | 1,744.79 ms | 1,738.34 | 1,767.53 | 63× | 403,496 |
| Pandoc + XeLaTeX | 2,651.78 ms | 2,638.93 | 2,696.45 | 95× | 305,037 |
Most of RayoMD's time with the PNG is decoding and re-encoding the 1024×1024 image. In one
running process (rayomd --bench DOC OUT 5000 modern normal) each further export takes 0.21 ms
without images and 0.25 ms with the PNG, which a running process caches.
All five write a six-page PDF of the PNG document but glu (nine pages, its own layout). RayoMD
and both Pandoc routes typeset the formulas; md-to-pdf and glu print them as TeX source, and
glu's default font has no Cyrillic or Greek letters. Both Pandoc routes print the fenced
math block as code.
In a container with the tools above (Pandoc's .deb, Typst's and glu's release archives,
npm install md-to-pdf@5.2.5, Debian's texlive-xetex texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended texlive-plain-generic lmodern fonts-dejavu-core chromium, PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium):
MD_TO_PDF_CHROME_ARGS=--no-sandbox python3 tools/benchmark.py competitors -- \
--rayomd rayomd-4.0.0-linux-x64/rayomd --node-modules /opt/node/node_modules \
--glu /opt/glu-linux-amd64/glu --document tester-noimg.md \
--pandoc-from markdown+tex_math_single_backslash-raw_tex \
--runs 20 --timeout 120 --preflight-timeout 120 --root benchmark-output/competitors-noimgRun it again with --document tester-local.md for the PNG document.
RayoMD alone was measured again in the same container a day later, beside 4.0.0, the other
tools not re-run: tester.md with its PNG in 9.7 ms with --no-image-cache (4.0.0 30.9 ms
that day), 2.6 ms once the image is in its cache; without images 1.37 ms (4.0.0 1.34 ms). The
comparison script now passes --no-image-cache to RayoMD builds that have it, so every run
converts the image as the other tools do. Details: RayoMD 4.1.0 Images 2026-10-13.