DEV Community

IronSoftware
IronSoftware

Posted on

pdf-lib in 2026: It Edits PDFs, It Cannot Render One

Here is pdf-lib doing the job it is built for, editing a PDF that already exists.

import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
import fs from "fs/promises";

const pdfDoc = await PDFDocument.load(await fs.readFile("contract.pdf"));
const page = pdfDoc.getPages()[0];
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);

page.drawText("Signed and dated", { x: 50, y: 50, size: 12, font, color: rgb(0, 0, 0) });

await fs.writeFile("contract-signed.pdf", await pdfDoc.save());
Enter fullscreen mode Exit fullscreen mode

Everything pdf-lib does is to a document that already exists, and every element is placed by an x and y coordinate. There is no call in the library that takes an HTML page and turns it into a PDF, because rendering was never in its scope. IronPDF for Node.js renders HTML through a Chromium engine and keeps the manipulation in the same object model, which is the difference this piece is about.

Full disclosure. We build IronPDF for Node.js at Iron Software, and this read looks at where pdf-lib's manipulation-only scope runs out and where IronPDF covers rendering and editing from one package.

What pdf-lib has no method for

The strong part, merging and stamping existing PDFs, is real. The gap is everything that starts from markup rather than coordinates.

  • No HTML or CSS rendering, at any level — pdf-lib builds documents from coordinate primitives, so it has no path for turning an HTML invoice, an email template, or a design handoff into a PDF, and a team that starts here for merging later runs a second library for the rendering half.
  • Text placement is manual — pdf-lib's drawText does not wrap lines or paginate, so any variable-length content, a generated report or a multi-paragraph letter, means writing your own layout engine on top of a library that has none.
  • The cadence has stalled — pdf-lib has not shipped a release since 1.17.1 in November 2021, its repository's last commit landed in July 2024, and 317 issues sit open, so a fix you need after that date is yours to write or fork.

On security, pdf-lib's own record is clean, with no CVEs on file across the GitHub Advisory Database, NVD, or Snyk. What a project with no commits since 2021 cannot show, though, is how quickly a newly found issue would actually get patched.

The split is in the rendering rows

The manipulation rows are close, and the rows that start from HTML are where the two split.

Capability pdf-lib IronPDF for Node.js
HTML and CSS to PDF Not supported Supported, PdfDocument.fromHtml
Text layout for new content Manual x/y positioning Automatic through HTML and CSS
Read existing text and metadata Form fields only Full text extraction
Merge, split, extract pages Supported Supported, PdfDocument.mergePdf
Form filling Supported Supported
Release cadence Last release November 2021 Active

Table 1. pdf-lib and IronPDF for Node.js across the rendering and manipulation questions, from pdf-lib's own README and npm metadata.

IronPDF renders where pdf-lib stops

IronPDF renders the HTML pdf-lib has no method for, then merges the result with an existing document from the same object model.

import { PdfDocument } from "@ironsoftware/ironpdf";

// Render HTML, the half pdf-lib has no method for
const invoice = await PdfDocument.fromHtml(
  "<h1>Invoice #1042</h1><p>Total due: $250.00</p>"
);

// Then merge with an existing document, same object model
const terms = await PdfDocument.open("terms-and-conditions.pdf");
const combined = await PdfDocument.mergePdf([invoice, terms]);

await combined.saveAs("invoice-with-terms.pdf");
Enter fullscreen mode Exit fullscreen mode

That renders a document and merges another onto it from one import, so the rendering and the manipulation are not two libraries with two mental models bolted together. You can pull IronPDF for Node.js from npm and run this render-and-merge path in a couple of minutes, and the HTML-to-PDF guide walks the rendering side end to end.

IronPDF covers the half pdf-lib skips

The one case for pdf-lib is a pipeline that only manipulates PDFs that already exist, merging, stamping, and filling forms, and never renders anything new. That holds only until HTML rendering enters the pipeline, though, which for most teams it eventually does, since a generated invoice or report starts as an HTML template far more often than as hand-placed coordinates.

At that point the choice is between bolting a renderer onto pdf-lib or covering both halves with IronPDF for Node.js from one package. IronPDF for Node.js has a free trial if you want to run your own HTML through it before deciding.

Are you already pairing pdf-lib with a separate renderer for the HTML half, or has that gap not come up yet? Tell us in the comments, we are curious how common that two-library setup is.

pdf-lib is an open-source project distributed under the MIT licence, and is not affiliated with Iron Software. The details above are drawn from the project's own README and npm metadata. If something has changed since, correct us in the comments.

Top comments (0)