Comparison
Compare renderer behavior and recorded invoice benchmarks.
This page records a benchmark of an 80-line invoice across three PDF renderers. The numbers apply to the package versions and environment below, not necessarily the current releases.
Each harness uses its engine's native template language. Geometry, columns, and the embedded font (Inter 400/700) are the same in each harness. react-pdf's pt values mirror the other renderers' px values. takumi and Chrome produce the same two-page layout.
Warm figures are the median of 20 renders. The bench source reproduces this table. Run it with bun bench.
Environment: Apple M1 Pro, macOS 15.7.4, Bun 1.3.14, Chrome 151.
| takumi-pdf 0.4 | @react-pdf/renderer 4.5.1 | Puppeteer + Chrome | |
|---|---|---|---|
| Cold start to first PDF | 176 ms | 495 ms | 0.7–2.8 s |
| Warm render (median) | 26 ms | 236 ms | 198 ms |
| Output size | 19 KB (15 KB with tagged: false) | 16 KB | 52 KB |
| Deploy needs | 1.5 MB gzip wasm | pure JS | Chrome install (hundreds of MB) |
| Template language | JSX, HTML, node trees with CSS and Tailwind | its own primitives (<View>, <Text>, StyleSheet) | HTML with full CSS |
| Selectable text, subset fonts | yes | yes | yes |
| Arabic and bidi text | yes | shaping only, manual direction | yes |
| Runs on edge runtimes | yes (Cloudflare Workers) | no (Node) | no |
Bundle and install size
These measurements use npm-registry packages and esbuild (--bundle --minify, gzip). Install size comes from a clean bun add.
| JS bundle (min+gzip) | wasm (gzip) | node_modules | |
|---|---|---|---|
| takumi-pdf 0.4 | 10 KB | 1.52 MB (1.16 MB brotli) | 4.2 MB, 45 files |
| @react-pdf/renderer 4.5.1 | 493 KB | — | 32 MB, 1998 files |
| pdf-lib 1.17.1 | 179 KB | — | 26 MB |
| pdfkit 0.19.1 | 253 KB | — | 23 MB |
| jspdf 4.2.1 | 248 KB | — | 59 MB |
| Puppeteer + Chrome | — | — | Chrome install (hundreds of MB) |
pdf-lib, pdfkit, and jspdf are drawing primitives. You position each text line yourself. They are not in the benchmark above.
Measure the complete bundle for your deployment target. These figures exclude application code and should not be used as a current platform size limit.
Interpret the results
- Chrome's cold start includes launching a browser process. It varies with machine state. Its memory spans several processes. A single-process measurement misses this. Chrome performs well after warming. It has the most complete CSS support of the three.
- react-pdf embeds the same Inter subsets as the other two. Subsetting on every render is most of its warm cost; the standard 14 PDF fonts avoid it. Documents use react-pdf's component set. Existing HTML, JSX, and Tailwind markup cannot be reused. It shapes Arabic, but paragraph direction is manual, and our Arabic sample dropped its first letter.
- takumi-pdf reuses OG-image components unchanged. Its CSS coverage is narrower than Chromium's. PDF output does not support
filter: blur(),drop-shadow(), orbackdrop-filter. A blurredbox-shadowis approximated with bands, and a blurredtext-shadowdraws sharp. Tagged output is on by default and adds about 4 KB to this invoice, down from 10 KB before the structure tree moved into an object stream.tagged: falseremoves it.
Choose based on your template and runtime. Puppeteer uses browser layout and executes page scripts. react-pdf uses document components. Takumi accepts HTML, JSX, and node trees with its supported CSS subset. Run your own documents through the benchmark before using these timings to estimate workload capacity.
Last updated on