docxtemplater, jszip, muhammara, pdf-lib, pdfkit, and xlsx are JavaScript libraries that enable frontend developers to generate, read, or modify document formats directly in the browser or Node.js environments. These packages target specific document types: docxtemplater and jszip focus on DOCX (via ZIP-based Office Open XML), muhammara and pdf-lib/pdfkit handle PDFs, and xlsx specializes in spreadsheet formats like XLSX and CSV. While some provide high-level templating or editing capabilities, others offer low-level binary manipulation. Understanding their scope, architecture, and runtime constraints is essential for choosing the right tool for document-heavy web applications.
When your web app needs to generate reports, export data, or let users edit documents in the browser, choosing the right library can make or break performance, maintainability, and user experience. The packages docxtemplater, jszip, muhammara, pdf-lib, pdfkit, and xlsx each solve different parts of the document puzzle — but they’re often confused because they overlap in format support (PDF, DOCX, XLSX) while differing wildly in capability and environment compatibility. Let’s cut through the noise with real engineering trade-offs.
Not all these libraries work in the browser — a dealbreaker for client-side apps.
docxtemplater, jszip, pdf-lib, pdfkit (with caveats), xlsxmuhammara (deprecated), pdfkit’s full feature setmuhammara is a native Node.js addon built on C++. It cannot run in the browser and its GitHub repo states it’s deprecated in favor of the unmaintained HummusJS. Do not use it in new projects.
pdfkit relies on fs and other Node.js APIs by default. To use it in the browser, you must bundle it with a Canvas implementation like canvas (which itself requires polyfills) — making it fragile for pure frontend use.
All others are written in pure JavaScript and work reliably in modern browsers.
pdfkit shines when you’re drawing custom layouts programmatically:
// pdfkit: Generate a new PDF with vector graphics
import PDFDocument from 'pdfkit';
import blobStream from 'blob-stream'; // for browser output
const doc = new PDFDocument();
const stream = doc.pipe(blobStream());
doc.fontSize(25).text('Hello from pdfkit!', 100, 100);
doc.moveTo(100, 200).lineTo(300, 200).stroke();
doc.end();
stream.on('finish', () => {
const blob = stream.toBlob('application/pdf');
// Trigger download
});
pdf-lib can also create new PDFs, but its API is less suited for complex drawings:
// pdf-lib: Create a new PDF (basic text only)
import { PDFDocument, StandardFonts } from 'pdf-lib';
const pdfDoc = await PDFDocument.create();
const page = pdfDoc.addPage([600, 400]);
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
page.drawText('Hello from pdf-lib!', {
x: 100,
y: 300,
size: 24,
font
});
const pdfBytes = await pdfDoc.save();
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
→ Use pdfkit for rich graphics; pdf-lib for simple text or when you’ll later edit the PDF.
Only pdf-lib supports this reliably in the browser:
// pdf-lib: Fill a form field in an existing PDF
import { PDFDocument } from 'pdf-lib';
const existingPdfBytes = await fetch('/form.pdf').then(res => res.arrayBuffer());
const pdfDoc = await PDFDocument.load(existingPdfBytes);
const form = pdfDoc.getForm();
const nameField = form.getTextField('name');
nameField.setText('John Doe');
const pdfBytes = await pdfDoc.save();
pdfkit cannot load or edit existing PDFs — it only generates new ones.
The xlsx library (from SheetJS) treats spreadsheets as data containers, not visual documents. It’s perfect for importing/exporting tabular data but weak on styling.
// xlsx: Export JSON data to XLSX
import * as XLSX from 'xlsx';
const data = [{ Name: 'Alice', Age: 30 }, { Name: 'Bob', Age: 25 }];
const ws = XLSX.utils.json_to_sheet(data);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'People');
// Generate blob for download
const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([wbout], { type: 'application/octet-stream' });
It can read user-uploaded files too:
// xlsx: Parse uploaded XLSX
const file = event.target.files[0];
const ab = await file.arrayBuffer();
const wb = XLSX.read(ab);
const ws = wb.Sheets[wb.SheetNames[0]];
const data = XLSX.utils.sheet_to_json(ws);
But don’t expect to replicate Excel’s conditional formatting or pivot tables — xlsx focuses on cell values and basic structure.
docxtemplater isn’t a general-purpose DOCX editor. It requires a pre-made .docx template with placeholders:
<!-- In your template.docx (as plain text inside Word) -->
Hello {name}, your invoice total is {total}.
Then fill it in code:
// docxtemplater: Fill a template
import Docxtemplater from 'docxtemplater';
import PizZip from 'pizzip'; // jszip fork used internally
const content = await fetch('/template.docx').then(res => res.arrayBuffer());
const zip = new PizZip(content);
const doc = new Docxtemplater(zip, {
paragraphLoop: true,
linebreaks: true
});
doc.render({
name: 'Alice',
total: '$100'
});
const out = doc.getZip().generate({ type: 'blob' });
You cannot build a DOCX from scratch with docxtemplater. For that, you’d need lower-level tools (none in this list do it well in the browser).
DOCX, XLSX, and PPTX are ZIP archives containing XML files. jszip lets you manipulate these archives directly:
// jszip: Extract content from a DOCX
import JSZip from 'jszip';
const arrayBuffer = await file.arrayBuffer();
const zip = await JSZip.loadAsync(arrayBuffer);
const wordDoc = await zip.file('word/document.xml').async('string');
// Now parse XML manually (not recommended for production)
But don’t use jszip alone for document logic — it has no awareness of OOXML schemas. Instead, it powers libraries like docxtemplater and xlsx under the hood. Only reach for it if you’re building a custom document processor.
| Task | Best Package | Why |
|---|---|---|
| Fill Word templates with data | docxtemplater | Abstracts OOXML complexity; safe for non-developer template authors |
| Export table data to Excel | xlsx | Handles XLSX/CSV round-tripping; minimal bundle impact |
| Add watermark to uploaded PDF | pdf-lib | Only browser-compatible PDF editor |
| Generate invoice PDF with charts | pdfkit | Superior drawing API for custom visuals |
| Read ZIP contents of any file | jszip | Pure JS; reliable archive manipulation |
| Edit existing PDF forms | pdf-lib | Full AcroForm support; works in browser |
| Server-side high-speed PDF gen | pdfkit (Node.js) | Faster than pdf-lib for large documents |
Users upload a DOCX template, then generate personalized reports from database records.
docxtemplater + jszip (implicitly)Export transaction history to Excel, and let users download filled tax forms as PDF.
xlsx (for XLSX) + pdf-lib (for PDF forms)Generate branded PDFs with charts and logos from scratch.
pdfkit (in Node.js backend)pdfkit’s drawing primitives; server avoids browser memory limits.muhammara: Marked deprecated, Node.js-only, no browser support. Avoid completely.jszip alone for DOCX/XLSX: You’ll reinvent broken XML parsers. Use docxtemplater or xlsx instead.pdfkit in browser without testing: Canvas polyfills add 300KB+ and may fail on mobile.Think in layers:
xlsxdocxtemplaterpdf-libpdfkitjszip (only as a last resort)And never, ever start a new project with muhammara.
These libraries solve narrow problems well — but only if you match their strengths to your actual use case. Pick the right tool, and your document workflows will feel effortless. Pick wrong, and you’ll drown in XML, binary buffers, or unsupported features.
Choose docxtemplater when you need to fill placeholders in pre-designed DOCX templates using structured data — ideal for generating invoices, reports, or letters from Word documents without manual layout code. It abstracts away the complexity of the OOXML format but requires a valid template file and doesn’t support creating DOCX from scratch. Avoid if you need dynamic layout control or programmatic document construction.
Choose jszip when you need to create, read, or modify ZIP archives in the browser — essential as a foundational layer for working with DOCX, XLSX, or PPTX files, which are ZIP containers. It doesn’t understand document semantics; use it only when you’re building or parsing custom archive-based formats or integrating with higher-level libraries like docxtemplater or xlsx. Not suitable for direct document content manipulation.
Avoid muhammara in new frontend projects — it is a C++-based Node.js addon with no browser support and has been deprecated in favor of HummusJS (which itself is unmaintained). It was designed for high-performance PDF creation and modification in server environments but cannot run in the browser due to native dependencies. Use pdf-lib instead for cross-environment PDF editing.
Choose pdf-lib when you need to modify existing PDFs or create new ones in both browser and Node.js environments with full Unicode and form support. It excels at tasks like filling form fields, adding watermarks, merging pages, or extracting text. Its API is modern, promise-based, and works without external dependencies. Prefer it over pdfkit if you must support client-side PDF manipulation or require PDF editing (not just generation).
Choose pdfkit when your primary goal is generating new PDFs from scratch with fine-grained vector graphics control (e.g., charts, diagrams, custom layouts) and you’re running in Node.js or a browser with a Canvas polyfill. It offers a fluent drawing API similar to HTML5 Canvas but cannot edit existing PDFs. Avoid if you need to modify uploaded PDFs or require robust browser-only support without additional shims.
Choose xlsx when working with spreadsheet data — reading user-uploaded XLSX/CSV files, exporting tabular data to Excel-compatible formats, or converting between sheet representations. It supports a wide range of formats and provides utilities for parsing and serializing workbook objects. Use it for data interchange scenarios, not for rich formatting or complex layout design, as its styling capabilities are limited compared to desktop Excel.
docxtemplater is a library to generate docx/pptx documents from a docx/pptx template. It can replace {placeholders} with data and also supports loops and conditions. The templates can be edited by non-programmers, for example your clients.
docxtemplater is very robust because of the many fixed issues over the years, and the high quality of tests and code.
The full documentation of the latest version can be found here.
See CHANGELOG.md for information about how to migrate from older versions.
Functionality can be added with the following paid modules :
{%image};{~html};{$chart};{~html};{:users};{:include doc};{:subsection doc};{:include doc};{r@wrun}. This makes it possible to include styled text without having to remove the enclosing paragraph like in the {@rawXml} tag;{:table data};{:stylepar style};{:footnotes foot}{?tag}Docxtemplater is my main job, and has been maintained for over 8 years. Expect to get great support if you buy any modules, and also good support on the open-source version.