Skip to content

Migrating from pdf-lib ​

HappyPDF is a fork of pdf-lib, so most code runs unchanged. This page covers what differs.

Install ​

bash
npm remove pdf-lib @pdf-lib/fontkit
npm install happypdf
js
// before
import { PDFDocument } from 'pdf-lib';

// after
import { PDFDocument } from 'happypdf';

Drop the fontkit registration ​

js
// before
import fontkit from '@pdf-lib/fontkit';
pdfDoc.registerFontkit(fontkit);
const font = await pdfDoc.embedFont(bytes);

// after
const font = await pdfDoc.embedFont(bytes);

registerFontkit still exists as a no-op, so leaving the call in place is harmless — it just does nothing.

Replace wordBreaks ​

The wordBreaks option, PDFDocument.defaultWordBreaks and the exported breakTextIntoLines have been removed. Break points now come from Intl.Segmenter, which handles the cases wordBreaks was used to work around.

js
// before
page.drawText(text, { maxWidth: 300, wordBreaks: [' ', '-'] });

// after
page.drawText(text, { maxWidth: 300 });

If you called breakTextIntoLines directly, use wrapText:

js
// before
const lines = breakTextIntoLines(text, [' '], 300, measure);

// after
const lines = wrapText(text, measure, { maxWidth: 300 }).map((l) => l.text);

Node 22 ​

HappyPDF requires Node 22 or newer, for Intl.Segmenter and modern module resolution. pdf-lib supported much older runtimes.

What you gain ​

  • Complex scripts render correctly
  • align: 'left' | 'center' | 'right' | 'justify'
  • variations for variable fonts
  • Wrapping at real word boundaries in every script

What is unchanged ​

Forms, SVG, images, page manipulation, encryption, PDF/A, annotations, JavaScript actions, and the entire object model. Existing pdf-lib knowledge and most existing code carry over directly.

Output differences ​

Text is written as one positioned glyph per operator rather than one string per line. The rendered result is the same or better, but if you compare content streams byte-for-byte, or parse your own output, expect different operators.

MIT Licensed. A fork of pdf-lib.