Skip to main content
Already using Puppeteer to generate PDFs? Here’s how to switch to pdfn.

Why migrate

Puppeteer gives you low-level browser control, but you end up managing a lot yourself:
  • Installing and updating Chromium binaries (250MB+)
  • Launching, reusing, and closing browser instances
  • Writing and managing print-related CSS for pagination
  • Working around Puppeteer’s limited header/footer API
  • Debugging layout differences between local and production Chromium versions
Puppeteerpdfn
TemplatesHTML strings or template enginesReact components
PaginationManualAutomatic
Headers / footersLimitedBuilt-in with <PageNumber>, <TotalPages>
Dev workflowNo previewLive preview with hot reload
InfrastructureYou manage Chromium, browser lifecycle, and deploymentManaged by pdfn Cloud (or self-host)
Dev / production parityVaries by Chromium versionIdentical output everywhere

Step 1: Install

npm install @pdfn/react
Add @pdfn/tailwind for Tailwind CSS support, and @pdfn/next for Next.js. See the Quickstart for details.

Step 2: Convert your templates

Replace HTML strings with React components using <Document> and <Page>:
function getInvoiceHtml(data: InvoiceData) {
  return `
    <html>
      <head>
        <style>
          body { font-family: Arial; padding: 40px; }
          h1 { font-size: 24px; }
          .total { font-weight: bold; font-size: 18px; }
        </style>
      </head>
      <body>
        <h1>Invoice #${data.number}</h1>
        <p>Customer: ${data.customer}</p>
        <p class="total">Total: $${data.total}</p>
      </body>
    </html>
  `;
}
Page size, margins, headers, and footers are declared in the template — no more passing options to page.pdf() or writing @page CSS.

Step 3: Replace the generation code

import puppeteer from 'puppeteer';

async function generatePdf(data: InvoiceData) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  await page.setContent(getInvoiceHtml(data), {
    waitUntil: 'networkidle0',
  });

  const pdf = await page.pdf({
    format: 'A4',
    printBackground: true,
    margin: { top: '1in', bottom: '1in', left: '1in', right: '1in' },
  });

  await browser.close();
  return pdf;
}
No browser to launch, no page lifecycle to manage.

Step 4: Remove Puppeteer

npm uninstall puppeteer
If you prefer to keep running your own Chromium, use client.render() instead of client.generate(). See Self-Hosting.

Next steps