DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
JavaScript

Node.js PDF Generation: PDFKit, pdf-lib, and Puppeteer for JavaScript and TypeScript

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For Node.js PDF generation, choose PDFKit to draw a document from code, pdf-lib to create or edit PDF structures, and Puppeteer to print an existing HTML/CSS page. There is no evidence-based universal winner: the right tool depends on the format your content is already in and whether you need to modify an existing PDF.

Choose the PDF approach that matches your source

Tool Best fit Main tradeoff
PDFKit Building printable documents from drawing primitives such as text, shapes, images, tables, and forms Node output is stream-based. Browser support has a narrower stream interface and cannot directly read filesystem paths.
pdf-lib Creating and modifying documents, including page operations, forms, and embedding pages You work with an explicit PDF-document editing model. Custom fonts require the documented fontkit integration.
Puppeteer Printing a page already laid out in HTML and CSS It automates browser printing rather than providing a direct PDF drawing API.

Use these questions to decide:

  • Is the document already HTML? Use Puppeteer when its browser-rendered layout and print styles should determine the PDF.
  • Are you composing pages from code? PDFKit provides drawing, layout, image, table, form, and related PDF-generation features.
  • Must you load or change an existing PDF? pdf-lib documents loading and modifying files as well as creating new ones.
  • Must the same code work beyond Node.js? pdf-lib documents support for Node, browsers, Deno, and React Native. PDFKit also supports Node and browsers, with different runtime constraints.

The official documentation describes capabilities, not a same-workload speed or memory comparison. If throughput or resource use decides the choice, benchmark your own document sizes, assets, and deployment environment rather than treating these tools as a performance ranking.

Generate a PDF with PDFKit

PDFKit is a drawing-oriented JavaScript library for Node.js and browsers. Its documented capabilities include text layout, vector paths and transformations, TrueType/OpenType/WOFF font embedding, JPEG and PNG images, tables, annotations, AcroForms, outlines, and security options. It suits multi-page printable documents assembled from application data.

Install and write a file in Node.js

Install the package with npm install pdfkit. This ES module example creates a document, pipes it to a writable file stream, writes content, and calls end() to finalize the PDF:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { createWriteStream } from 'node:fs';
import { PDFDocument } from 'pdfkit';

const doc = new PDFDocument({ size: 'A4', margin: 50 });
doc.pipe(createWriteStream('report.pdf'));
doc.fontSize(20).text('Monthly report', { align: 'center' });
doc.moveDown();
doc.fontSize(12).text('Generated from Node.js data.');
doc.end();

The package documentation also shows CommonJS use with the named export: const { PDFDocument } = require('pdfkit'). Use the import style supported by your project configuration.

Stream to an HTTP response

In Node, a PDFKit document is a readable stream. It can be piped to an HTTP response instead of a file. Set the response headers before piping so the client handles the output as a PDF:

app.get('/report.pdf', (req, res) => {
  res.setHeader('Content-Type', 'application/pdf');
  res.setHeader('Content-Disposition', 'inline; filename="report.pdf"');

  const doc = new PDFDocument({ size: 'A4', margin: 50 });
  doc.pipe(res);
  doc.fontSize(18).text('Report');
  doc.end();
});

In a real application, make sure every success and error path is handled by the surrounding server framework. Do not omit doc.end(): it signals that document writing is complete.

Assets and browser use

The Node build has filesystem access, native zlib compression, and Node streams. The browser build omits Node’s stream module and filesystem access. If a browser capture uses an image or font from a filesystem path, register or provide its bytes rather than expecting the browser build to read that path directly. PDFKit’s toBlob and toBytes helpers under pdfkit/output are described as experimental, so do not make them a production dependency without checking their current status in the project documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create or edit a PDF with pdf-lib

pdf-lib uses an explicit document model: create or load a document, perform page and content operations, then serialize it. Its documentation covers adding, inserting, and removing pages; drawing text, images, and vector graphics; embedding pages; and creating or filling forms. The project says it is written in TypeScript, compiled to pure JavaScript, and works in Node.js, browsers, Deno, and React Native.

Create a new PDF

Install with npm install --save pdf-lib. The following creates a one-page PDF and writes the serialized bytes:

import { writeFile } from 'node:fs/promises';
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';

const pdfDoc = await PDFDocument.create();
const page = pdfDoc.addPage([595.28, 841.89]);
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);

page.drawText('Monthly report', {
  x: 50,
  y: 780,
  size: 20,
  font,
  color: rgb(0.1, 0.2, 0.4),
});

const bytes = await pdfDoc.save();
await writeFile('report.pdf', bytes);

Load and modify an existing PDF

Use PDFDocument.load() when you need to edit a PDF rather than print an HTML page. This example adds text to the first page, then saves a new file:

import { readFile, writeFile } from 'node:fs/promises';
import { PDFDocument, StandardFonts } from 'pdf-lib';

const input = await readFile('source.pdf');
const pdfDoc = await PDFDocument.load(input);
const pages = pdfDoc.getPages();

if (pages.length === 0) {
  throw new Error('The source PDF has no pages');
}

const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
pages[0].drawText('Reviewed', { x: 50, y: 40, size: 10, font });

await writeFile('reviewed.pdf', await pdfDoc.save());

For a custom font, the documented approach registers @pdf-lib/fontkit before embedding the font bytes. Follow the library’s font-embedding example rather than assuming built-in fonts can represent every character set.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Print HTML and CSS with Puppeteer

Choose Puppeteer when the desired PDF is the print rendering of a browser page. Its documented flow is to launch a browser, open a page, navigate to a URL, call page.pdf(), and close the browser. The PDF guide displayed version 25.12.0 when accessed on September 29, 2026; check the current documentation for the version matching your installed package.

Runnable Node.js example

Install Puppeteer with npm install puppeteer, then save this as an ES module:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();

try {
  const page = await browser.newPage();
  await page.goto('https://example.com', { waitUntil: 'networkidle0' });
  await page.pdf({ path: 'page.pdf', format: 'A4' });
} finally {
  await browser.close();
}

Page.pdf() prints using print CSS media and waits for fonts to load by default, according to the guide. That makes print-specific CSS—such as page breaks, margins, and content visibility—part of the PDF output. If your application has a local HTML template, load that page in the browser instead of navigating to a public URL, and ensure required assets are reachable before printing.

Practical selection and implementation checks

Think in terms of document ownership

  • Application owns every element: PDFKit is a natural fit when code constructs text, geometry, tables, images, and forms.
  • PDF file is the thing being transformed: pdf-lib is the closer fit for page manipulation, embedded pages, or form work.
  • Web page owns the layout: Puppeteer is appropriate when the screen/print HTML is the source of truth.

Account for output shape

PDFKit in Node writes through streams, which works well with file and HTTP destinations; ensure the stream lifecycle is completed. pdf-lib examples serialize a document with save(), yielding bytes that your application then stores or sends. Puppeteer returns a browser-generated PDF from page printing. These differing interfaces affect how you connect generation to storage, HTTP responses, and job queues.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Validate what readers receive

  • Check page count, page size, margins, page breaks, and long-content behavior using representative documents.
  • Include real images, fonts, and non-ASCII text in validation; missing assets or unsupported glyphs may not be apparent in a minimal sample.
  • For browser printing, check the print-media appearance rather than relying only on the normal screen view.
  • For PDF editing, test source documents from the range your application accepts, including empty or unusual page structures where relevant.
  • If performance, memory, or concurrency matters, measure that workload in the target runtime; official descriptions do not establish a fair cross-library winner.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot common PDF generation failures

The output file is empty, incomplete, or unreadable

With PDFKit, verify that the document is piped to a writable destination and that doc.end() is called after all content is added. With pdf-lib, await save() and write the returned bytes. With Puppeteer, await page.pdf() before closing the browser.

Images or fonts are missing

Check that asset paths resolve in the runtime where generation occurs. The PDFKit browser build cannot directly access filesystem paths; supply registered bytes for those assets. For pdf-lib custom fonts, use the documented fontkit integration. With Puppeteer, ensure the page has loaded the resources it needs before printing; its PDF method waits for fonts by default, but that does not make an unavailable font file reachable.

The printed page looks different from the browser preview

Puppeteer’s PDF method uses print CSS media. Add or adjust print-specific styles and inspect page breaks, hidden elements, and dimensions in the PDF output. The guide says fonts are awaited by default, so investigate missing network assets or CSS differences if typography still changes.

The code cannot load the PDF or an asset

Confirm the input file exists, the path is valid for the Node process, and the process has permission to read it. For browser execution, replace filesystem-only assumptions with bytes available to the browser. For pdf-lib, confirm the input is a supported PDF and that loading completes before editing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

ScreenshotNeo is not a PDF-generation SDK

ScreenshotNeo is a website screenshot API and MCP server, not a replacement for PDFKit, pdf-lib, or Puppeteer’s PDF printing. It is relevant if your task is to capture a webpage as an image or PDF without maintaining your own browser-capture setup. See ScreenshotNeo for the service overview.

Or skip the browser setup

One GET request can return a screenshot as PNG, JPEG, or WebP, or a PDF. For a webpage PDF, use format=pdf:

curl -G "https://api.screenshotneo.com/v1/shot" 
  -d access_key=YOUR_API_KEY 
  --data-urlencode url=https://example.com 
  -d format=pdf 
  -o page.pdf

Parameter names used by other screenshot APIs also work. The ScreenshotNeo API documentation describes its request options. Cookie banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, with response headers indicating the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Sign up free for 1,000 screenshots a month, with no card required.

Frequently asked questions

Can I use these libraries from TypeScript?

Yes. pdf-lib says it is written in TypeScript and compiled to pure JavaScript. PDFKit and Puppeteer are JavaScript packages commonly used from TypeScript projects; check the current package documentation and type support for the versions you install.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can I turn a webpage into a PDF without rebuilding its layout?

Yes. Puppeteer’s Page.pdf() prints a browser page and is the documented option here for HTML/CSS layouts. ScreenshotNeo can also return a webpage PDF from its screenshot API when you prefer a hosted capture request.

Which option should I choose for merging or splitting PDFs?

pdf-lib’s official overview documents splitting and merging as supported use cases, alongside page insertion, removal, and embedding.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.