HtmlToPdf vs. Grover vs. WickedPdf/PDFKit vs. Prawn — what each one actually renders, what it depends on, and which question to ask before picking one.
The first question is not "which gem" — it's "do I want to render my existing view, or build the PDF's layout from scratch." Prawn is the only contender here that doesn't render HTML/CSS at all; everything else in this comparison converts an HTML page, the difference is how.
| Capability | HtmlToPdf | Grover | WickedPdf / PDFKit | Prawn |
|---|---|---|---|---|
| Renders existing HTML/CSS view | ✓ | ✓ | ✓ | — (own DSL) |
| Rendering engine | Chrome (CDP, direct) | Chrome (via Node/Puppeteer) | wkhtmltopdf | n/a |
| Modern CSS (flexbox/Grid) | ✓ | ✓ | — | n/a |
| Runtime outside Ruby | Chrome/Chromium | Chrome + Node.js + Puppeteer | wkhtmltopdf binary | none |
| Pooled/reused browser process | ✓ (built in) | depends on setup | n/a (CLI per call) | n/a |
| Rails controller integration | built in (around_action) | manual | built in | manual |
| Precise pixel-level layout control | via CSS | via CSS | via CSS (limited) | ✓ (direct PDF primitives) |
Headless Chrome driven directly over the DevTools protocol via
ferrum — no Node.js in the dependency chain.
One pooled browser process per Ruby process (see
BrowserPool),
each render in its own isolated context. Ships as an around_action, so other
callbacks and rescue_from work exactly as they would for a normal request — see
why that specific detail is harder to get right than it
looks. The narrowest print-options surface of the HTML-rendering contenders here: every
option is a validated number/enum/boolean except header/footer templates, which are opt-in only
(see Security).
Best fit if you want Chrome-quality rendering without adding Node.js to a pure-Ruby/Rails stack.
Also headless Chrome, via Puppeteer — which
means Node.js and the puppeteer npm package become real dependencies alongside the
Ruby gem, not just an implementation detail. If your deploy already runs a Node toolchain for
other reasons, that cost is close to zero; if it doesn't, it's a second language runtime to
install, patch, and reason about solely for PDF export. Puppeteer's own PDF generation API
(native header/footer templates, `waitUntil` semantics) is mature and well-documented
independent of Grover itself.
Both wrap the wkhtmltopdf binary — see Headless Chrome vs. wkhtmltopdf for what that costs you in rendering fidelity (no flexbox/Grid, years-stale WebKit, an unmaintained upstream project). The appeal is real, though: a single static binary is operationally simpler to deploy than a full Chrome install, and for simple layouts — plain text, basic tables, no modern CSS — the rendering gap may never actually surface. If your PDF output is that simple and you'd rather not add a browser to your stack, this is a legitimate reason to stay.
A fundamentally different tool, not a wkhtmltopdf/Chrome alternative: Prawn has no HTML/CSS engine at all. It's a Ruby DSL for drawing PDF content directly — text blocks, tables, shapes, positioned by hand. Choosing Prawn means writing your PDF's layout as Prawn code instead of reusing an existing view, full stop; there's no middle ground where you point it at an ERB template. The payoff is precision: exact pixel-level control over a PDF a browser-rendering approach can only approximate through CSS. Right tool when the PDF's layout needs don't actually match your HTML view's layout at all — a label sheet, a check, a precisely-gridded form — not when the goal is "render this page as a PDF."