Convert documents in Node.js: open-source tools explored
Document conversion is a frequent requirement in Node.js applications, whether you're generating PDFs from HTML, creating invoices, or exporting reports. Fortunately, the Node.js ecosystem provides several robust open-source libraries to simplify these tasks. Let's explore some of the best options available, along with practical examples to help you select the right tool for your project.
These examples render or generate PDFs; they do not convert arbitrary Word, spreadsheet, or PDF
files into other editable formats. Use Node.js 22.12 or later for the server examples and save each
as a separate .cjs file. The jsPDF example runs in a browser.
Popular open-source libraries for document conversion
Here are some widely used libraries:
- Puppeteer: Headless Chrome automation for HTML-to-PDF conversion.
- PDFKit: Server-side PDF generation with extensive customization.
- jsPDF: Client-side PDF generation directly in the browser.
- wkhtmltopdf: Archived command-line tool for legacy HTML-to-PDF workflows.
Let's dive deeper into each of these.
Html-to-pdf conversion with Puppeteer
Puppeteer is a powerful Node.js library offering a high-level API to control headless Chrome (or Chromium), making it ideal for converting HTML pages into PDFs. It accurately renders web pages, including CSS and JavaScript.
Example usage
Install Puppeteer, which also downloads a compatible Chrome browser:
npm install puppeteer@25
Only render URLs and HTML that you control. A production service accepting arbitrary URLs needs network isolation and request validation to prevent access to internal services.
const puppeteer = require('puppeteer')
async function htmlToPdf(url, outputPath) {
const browser = await puppeteer.launch()
try {
const page = await browser.newPage()
const response = await page.goto(url, { waitUntil: 'networkidle0' })
if (!response || !response.ok()) {
throw new Error(`Page load failed: ${response?.status() ?? 'no HTTP response'}`)
}
await page.pdf({ path: outputPath, format: 'A4' })
} finally {
await browser.close()
}
}
htmlToPdf('https://example.com', 'example.pdf').catch((error) => {
console.error(error.message)
process.exitCode = 1
})
Pros and cons
- Pros: Accurate rendering, supports modern CSS and JavaScript, can handle Single Page Applications (SPAs).
- Cons: Higher resource usage due to the headless browser, can be slower than other methods.
Generating PDFs with PDFKit
PDFKit is a versatile library for creating PDFs programmatically on the server-side. It allows for fine-grained control over the PDF's content and layout.
Example usage
npm install pdfkit@0.17
Wait for the output stream to finish so disk errors are reported before declaring success:
const PDFDocument = require('pdfkit')
const fs = require('fs')
const { pipeline } = require('node:stream/promises')
async function createPdf(outputPath) {
const doc = new PDFDocument()
const writing = pipeline(doc, fs.createWriteStream(outputPath))
try {
doc.fontSize(25).text('Hello, PDFKit!', 100, 100)
doc.fontSize(12).text('This is a sample PDF generated using PDFKit.', 100, 150)
doc.end()
} catch (error) {
doc.destroy(error)
}
await writing
}
createPdf('output.pdf').catch((error) => {
console.error(error.message)
process.exitCode = 1
})
Pros and cons
- Pros: Highly customizable, lightweight, good for generating PDFs from scratch.
- Cons: Requires manual layout management, can be complex for intricate designs.
Client-side PDF generation with jsPDF
jsPDF enables PDF generation directly in the browser, often combined with html2canvas for capturing HTML content and converting it to an image, which is then added to the PDF.
Example usage
<script src="https://cdn.jsdelivr.net/npm/jspdf@4.2.1/dist/jspdf.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
<div id="content">Hello, jsPDF!</div>
<button id="download">Download PDF</button>
<p id="status" role="status"></p>
<script>
async function generatePDF() {
const { jsPDF } = window.jspdf
const content = document.getElementById('content')
const canvas = await html2canvas(content)
const imgData = canvas.toDataURL('image/png')
const pdf = new jsPDF()
const width = pdf.internal.pageSize.getWidth() - 20
const height = pdf.internal.pageSize.getHeight() - 20
const scale = Math.min(width / canvas.width, height / canvas.height)
pdf.addImage(imgData, 'PNG', 10, 10, canvas.width * scale, canvas.height * scale)
pdf.save('download.pdf')
}
document.getElementById('download').addEventListener('click', async () => {
const status = document.getElementById('status')
status.textContent = ''
try {
await generatePDF()
} catch {
status.textContent = 'Unable to generate the PDF. Please try again.'
}
})
</script>
This fits a screenshot onto one page. Long content becomes smaller, and the resulting image has no selectable text or document structure for screen readers. Use a text-based PDF layout when those capabilities are required; html2canvas also needs same-origin or CORS-enabled image assets.
Pros and cons
- Pros: No server-side processing required, easy integration, suitable for client-side applications.
- Cons: Limited styling and layout control compared to server-side solutions, rendering may differ slightly from the original HTML due to html2canvas limitations.
Advanced conversion with wkhtmltopdf
wkhtmltopdf converts HTML to PDF using an old Qt WebKit engine. Its repository was archived in January 2023, and it is no longer maintained. This example is for existing installations processing trusted HTML only. The project’s security guidance warns against untrusted input. Use a maintained renderer such as Puppeteer for new applications.
Example usage
const { execFile } = require('node:child_process')
execFile('wkhtmltopdf', ['https://example.com', 'output.pdf'], (error) => {
if (error) {
console.error(`Error: ${error.message}`)
process.exitCode = 1
return
}
console.log('PDF generated successfully')
})
Pros and cons
- Pros: Can preserve existing batch workflows built around its older rendering engine.
- Cons: Requires an external binary, lacks maintenance and modern browser compatibility, and must not process untrusted HTML.
Choosing the right library
Consider these factors when selecting a library:
- Complexity: Puppeteer supports modern layouts and dynamic content. Reserve wkhtmltopdf for trusted legacy workflows.
- Performance: PDFKit is lightweight and fast for generating simple PDFs from scratch. If speed is critical and your PDF structure is relatively simple, PDFKit is a strong contender.
- Environment: jsPDF is ideal for client-side applications where you want to generate PDFs directly in the user's browser.
- Dependencies: wkhtmltopdf requires a separate binary installation, while the others are pure Node.js libraries (although Puppeteer manages its own Chromium/Chrome binary).
Evaluate your project's specific needs to choose the best fit. For example, if you need to generate invoices with a consistent layout, PDFKit might be a good choice. If you need to convert a complex, JavaScript-heavy web page to PDF, Puppeteer would be more suitable.
Transloadit's document conversion
If you're looking for a managed solution, Transloadit's
Document Processing service offers robust document conversion
capabilities through its /document/convert Robot. You can easily integrate this into your Node.js
applications using our node-sdk.
