Guides

How to convert HTML to PDF in Node.js (2026 guide)

Generating a PDF from HTML is the most practical way to produce invoices, reports and receipts in a Node.js app: you already know HTML and CSS, and a browser engine handles layout, fonts and pagination for you. This guide covers the three approaches that work in 2026, with code you can paste.

Option 1: Puppeteer

Puppeteer drives headless Chrome. It gives the most faithful output, because it's literally Chrome's print engine.

npm install puppeteer
import puppeteer from "puppeteer";

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent("<h1>Invoice #1042</h1><p>Total: $120.00</p>", { waitUntil: "load" });
const pdf = await page.pdf({ format: "A4", printBackground: true, margin: { top: "20mm", bottom: "20mm" } });
await browser.close();
// pdf is a Uint8Array; write it to disk or send it in a response

To render an existing page instead, replace setContent with await page.goto(url, { waitUntil: "networkidle2" }).

Option 2: Playwright

Playwright's API is almost identical. Only Chromium supports page.pdf().

import { chromium } from "playwright";

const browser = await chromium.launch();
const page = await browser.newPage();
await page.setContent(html);
const pdf = await page.pdf({ format: "Letter", printBackground: true });
await browser.close();

Production pitfalls with self-hosted Chrome

Both libraries work fine on a laptop. In production, these are the problems teams usually hit:

Option 3: a hosted HTML to PDF API

If you'd rather not run browsers at all, send the HTML to an API and get the PDF back. With PDFLoom, that's one request:

const res = await fetch("https://pdfloom.dev/v1/pdf", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PDFLOOM_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ html, format: "A4", margin: "20mm" }),
});
if (!res.ok) throw new Error((await res.json()).error);
const pdf = Buffer.from(await res.arrayBuffer());

Rendering still uses real Chrome, so the output matches Puppeteer, but memory, fonts, timeouts and SSRF protection are handled for you. The free plan includes 100 PDFs a month. Get an API key.

Which should you pick?

CSS tips for good-looking PDFs

@page { size: A4; margin: 16mm; }
h2 { break-after: avoid; }
tr, .card { break-inside: avoid; }
.new-page { break-before: page; }
body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }

See also: adding page numbers, headers and footers.


More guides