Comparison
HTML templates instead of pdf-lib coordinate drawing
pdf-lib is a powerful JavaScript library for creating and modifying PDF files at the binary level. You position text with x/y coordinates, embed fonts explicitly, and handle page geometry manually. This is the right tool when you need to programmatically manipulate existing PDFs. When the goal is generating a new document from structured data (an invoice, a report, a certificate) PDFPipe lets you write HTML and CSS, including the Tailwind or Bootstrap your team already uses for every other layout task, and renders it to a PDF for you.
pdf-lib versus PDFPipe
| PDFPipe | pdf-lib | |
|---|---|---|
| Layout language | HTML + CSS | x/y coordinates in code |
| Font handling | Web fonts, system fonts automatic | Manual embed from bytes |
| Tables and lists | Native HTML elements | Manual rows, column math |
| Page breaks | CSS print rules | Manual newPage() calls |
| Template iteration speed | Edit HTML/CSS and re-render | Rewrite coordinate code |
| PDF modification | Not the primary use case | Excellent: merge, split, annotate |
| Runs on server | Yes (API call) | Yes (library) |
| AI agents | First-class MCP server | Requires custom tooling |
The coordinate approach scales poorly
A pdf-lib invoice implementation typically starts with placing a header atdrawText("Invoice", { x: 50, y: 750 }). When the line-item table grows by one row, every element below it needs its y-coordinate manually decremented. When a customer name is longer than expected, it clips or overlaps. When the design changes, the entire coordinate grid needs recalculating.
HTML and CSS handle all of this with flow layout: elements push each other down, text wraps, tables grow to fit content. Designers can iterate on the template without touching JavaScript. PDFPipe renders that template with a full browser engine, so the output matches what you see in a browser at A4 print size.
When pdf-lib is still the right choice
pdf-lib is the right tool when you need to programmatically manipulate existing PDFs: merging documents, filling form fields in an existing template, adding digital signatures, splitting pages, or annotating PDFs. For those tasks it has no close peer in JavaScript. PDFPipe is the better choice when you are generating new documents from data.
Using PDFPipe from Node.js
const html = `
<style>
body { font-family: system-ui; padding: 40px; }
table { width: 100%; border-collapse: collapse; }
td { padding: 8px; border-bottom: 1px solid #eee; }
</style>
<h1>Invoice #${orderId}</h1>
<table>
${lineItems.map(i => `<tr><td>${i.name}</td><td>${i.amount}</td></tr>`).join("")}
</table>
`;
const res = await fetch("https://api.pdfpipe.xyz/v1/pdf", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PDFPIPE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ html, options: { format: "A4" } }),
});
const buffer = Buffer.from(await res.arrayBuffer());