How to Merge PDFs in Node.js (Without a 300-Line Library Setup)
PDF merging in Node.js has a few popular approaches, and they all converge on the same frustrating place: pdf-lib, hummus, or calling out to a Python script wrapping PyPDF2.
These work. But they're not lightweight. pdf-lib is capable, but merging PDFs with complex features — embedded fonts, form fields, digital signatures — can produce broken output. And when it breaks, the error messages are not helpful.
The Setup
npm install renderpdfs
Merging Two PDFs
import RenderPDFs from 'renderpdfs';
const client = new RenderPDFs('rpdf_your_key');
const merged = await client.merge([
'https://example.com/files/contract.pdf',
'https://example.com/files/appendix.pdf',
]);
import { writeFileSync } from 'fs';
writeFileSync('combined.pdf', merged);
The input is an array of PDF URLs. The output is a single merged PDF Buffer.
Real Use Case: Bundling a Contract with Its Attachments
app.post('/contracts/:id/bundle', authenticate, async (req, res) => {
const contract = await db.contracts.findById(req.params.id);
const attachments = await db.attachments.findByContractId(contract.id);
const pdfUrls = [contract.pdfUrl, ...attachments.map(a => a.pdfUrl)];
if (pdfUrls.length < 2) {
return res.status(400).json({ error: 'Nothing to merge' });
}
const merged = await client.merge(pdfUrls);
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', `attachment; filename="contract-${contract.id}-bundle.pdf"`);
res.send(merged);
});
Generate + Merge in One Flow
// Step 1: Generate a cover page
const { url: coverUrl } = await client.generate({
html: `<html><body style="font-family:sans-serif;padding:60px;text-align:center;">
<h1 style="margin-top:200px;">${title}</h1>
<p style="color:#555;">${subtitle}</p>
</body></html>`,
store: true,
});
// Step 2: Merge cover + body
const packet = await client.merge([coverUrl, existingDocumentUrl]);
res.setHeader('Content-Type', 'application/pdf');
res.send(packet);
Error Handling
try {
const merged = await client.merge(urls);
} catch (err) {
if (err.status === 422) {
return res.status(400).json({ error: 'One or more PDF sources are invalid' });
}
throw err;
}
Getting Started
npm install renderpdfs
100 PDFs/month free at renderpdfs.com. API docs at renderpdfs.com/docs.
Top comments (0)