If you've ever generated PDFs on a backend — invoices, reports, receipts — you've probably used Puppeteer or Playwright. They work, but they're slow.
Spinning up a headless Chrome instance to render a simple invoice takes 2–4 seconds, eats 300+ MB of RAM, and cold starts in serverless environments are brutal.
I needed something faster. So I built html-pdf-lite — a lightweight HTML-to-PDF converter for Node.js that skips Chrome entirely.
How fast?
| Engine | Time per PDF | Memory |
|---|---|---|
| Puppeteer | 2–4s | ~300 MB |
| html-pdf-lite | 200–400ms | ~50 MB |
That's 10x faster with 6x less memory.
How it works
Instead of launching a browser, html-pdf-lite:
- Parses HTML with JSDOM
- Applies CSS cascade (specificity, inheritance, variables, shorthands)
- Renders directly to PDF using PDFKit
No Chrome. No Playwright. No browser binary to install.
npm install html-pdf-lite
const { renderPdfFromHtml } = require('html-pdf-lite');
const fs = require('fs');
const html = `
<h1>Invoice #1042</h1>
<table>
<tr><td>Widget</td><td>$10.00</td></tr>
<tr><td>Gadget</td><td>$25.00</td></tr>
</table>
<p><strong>Total: $35.00</strong></p>
`;
const pdf = await renderPdfFromHtml(html);
fs.writeFileSync('invoice.pdf', pdf);
That's it. One function, returns a Buffer.
What it supports
- Headings, paragraphs, spans, links
- Tables with colspan and styled cells
- Flexbox and CSS Grid layout
- Ordered and unordered lists
- Images (PNG, JPEG, SVG, data URIs)
- Inline SVG rendering
- Page breaks (
break-before,break-inside: avoid) - Internal PDF links (
href="#section") - CSS variables, shorthands, specificity cascade
- Custom fonts with system font auto-detection
-
@pagemargin rules
What it doesn't support
This is not a full browser engine. If you need:
- Perfect flexbox/grid parity with Chrome
- JavaScript-rendered content
- Advanced CSS (animations, transforms, filters)
Use Puppeteer. That's the right tool for those cases.
html-pdf-lite is for when you have a known HTML template and need a PDF fast — APIs, invoices, reports, serverless functions.
Perfect for serverless
No Chromium binary means:
- Deploys to AWS Lambda without layers or custom runtimes
- Works on Vercel, Cloudflare Workers, Railway
- Cold starts in milliseconds, not seconds
- Fits in small container images
Open source
MIT licensed. 11 test suites. CI on every push.
GitHub: github.com/BohdanShtelmakh/html-to-pdf
npm: npmjs.com/package/html-pdf-lite
If it helped you, star the repo. If something doesn't render right, open an issue with a minimal HTML example and I'll fix it.
Top comments (0)