`pdf-lib` is a robust and actively maintained JavaScript library designed for creating and modifying PDF documents in any modern JavaScript environment, including Node.js, browsers, Deno, and React Native. Currently at version 1.17.1, it receives frequent minor and patch releases, with major versions introducing significant architectural changes. A key differentiator of `pdf-lib` from many other open-source PDF libraries is its comprehensive support for *modifying* existing PDF documents, not just creating new ones. Its features include drawing text, images, and vector graphics, embedding fonts (with UTF-8 and UTF-16 support), managing pages (add, insert, remove, copy), creating and filling forms, and setting/reading document metadata and viewer preferences. The library is written in TypeScript, providing excellent type support for its users.
npm install pdf-libVerified import paths — ran on the pinned version, not inferred.
This example demonstrates creating a new PDF document, embedding a standard font, adding a page, drawing text, and serializing the document to bytes.
Ensure all calls to `create()`, `load()`, and `save()` are `await`ed. Update `PDFDocumentFactory` references to `PDFDocument`. Refactor drawing logic to use direct `page.draw...` methods. Replace `getMaybe` with `get` and use `PDFName.of()` for string keys.
Install `@pdf-lib/fontkit` via npm (`npm install @pdf-lib/fontkit`) and register it before attempting to embed custom fonts: `import fontkit from '@pdf-lib/fontkit'; pdfDoc.registerFontkit(fontkit);`.
If custom fonts are not needed, avoid installing `@pdf-lib/fontkit`. For browser environments, consider using CDN builds that don't include `fontkit` if feasible, or optimize your build process. Recent versions (post v0.5.1) have seen bundle size reductions.
Avoid using `pdf-lib` with encrypted documents. If encryption is a requirement, preprocess the PDF to remove encryption before using `pdf-lib` or consider alternative solutions designed for encrypted PDF handling.
Update method calls from `embedJPG` to `embedJpg` and `embedPNG` to `embedPng`.
Ensure `PDFDocument.create()` and `PDFDocument.load()` are awaited, as they return Promises since v1.0.0: `const pdfDoc = await PDFDocument.create();`
Validate the original PDF with external tools (e.g., qpdf) if possible. Try simplifying the operations performed on the PDF. If re-saving an existing PDF, try `pdfDoc.save({ useObjectStreams: false })` as a workaround for some legacy viewer issues. Ensure embedded fonts are correctly registered and compatible.Rename `pdfDoc.embedJPG()` to `pdfDoc.embedJpg()` and `pdfDoc.embedPNG()` to `pdfDoc.embedPng()`.
For text containing characters outside WinAnsi (e.g., Unicode characters, emojis), embed a custom font that supports the required character set (e.g., `fontBytes = await fetch('/path/to/my-font.ttf').then(res => res.arrayBuffer()); const customFont = await pdfDoc.embedFont(fontBytes);`). Remember to install and register `@pdf-lib/fontkit` for custom fonts.Replace `getMaybe` calls with `get`. If looking up a string-based dictionary key, wrap the string in `PDFName.of()`: `pdfDoc.catalog.get(PDFName.of('AcroForm'))`.