Sign in
BlogDeveloper guides

Convert DOCX to PDF in Node.js: every option compared

There is no free, pure-JavaScript library that reliably converts DOCX to PDF. Every approach involves a trade-off: LibreOffice (500 MB binary), commercial SDKs (Nutrient, Apryse, Aspose), hosted APIs (per-document pricing), or skipping conversion entirely by generating both formats from JSON. Here's when to use each.

There is no free, pure-JavaScript library that reliably converts DOCX to PDF. DOCX is a complex format — paragraph spacing, section breaks, table layout, headers, footers, font metrics — and rendering it as PDF requires a layout engine that understands Word's formatting model. Every approach involves a trade-off: LibreOffice (free, 500 MB binary), commercial SDKs (no external deps, $$$), hosted APIs (per-document pricing), or skip conversion (generate both formats from JSON). Here is every option, honestly.

Overview

ApproachToolsCostExternal binaryServerlessFidelity
LibreOffice headlesslibreoffice-convert, unoconv, GotenbergFree500+ MBNoHigh
Commercial SDKNutrient, Apryse, Aspose.Words$500–$2,000+/yrNative binary (50–200 MB)LimitedHigh
Hosted APIConvertAPI, CloudConvert, Adobe PDF ServicesPer-documentNoneYesHigh
Skip conversionPaperJSX$149/moNone (pure JS)YesSchema-defined

Option 1: LibreOffice headless (free, heavy)

LibreOffice implements a Word-compatible layout engine. The libreoffice-convert npm package wraps it in a Node.js-friendly API. According to Nutrient's comparison, this approach "works well for basic conversion needs" but requires managing LibreOffice as a system dependency.

import { convert } from "libreoffice-convert";
import { readFileSync, writeFileSync } from "node:fs";
import { promisify } from "node:util";

const convertAsync = promisify(convert);
const docx = readFileSync("invoice.docx");
const pdf = await convertAsync(docx, ".pdf", undefined);
writeFileSync("invoice.pdf", pdf);

Pros: Free. Best open-source fidelity for complex Word layouts. Handles headers, footers, section breaks, embedded images, tracked changes.

Cons: Requires LibreOffice installed on the host (~500 MB). Spawns external processes — needs process management and health checks. Docker images are 500+ MB. Cannot run on Vercel, Cloudflare Workers, or standard Lambda. Output varies between LibreOffice versions. According to Nutrient's analysis, it offers "limited error reporting compared to integrated solutions."

Docker alternative: Gotenberg packages LibreOffice and Chromium in a Docker container with an HTTP API. Run it as a sidecar service — your app sends the DOCX via HTTP and receives the PDF. This isolates the LibreOffice dependency from your application container.

Option 2: Commercial SDKs (no LibreOffice)

Three commercial SDKs implement their own DOCX layout engines, eliminating the LibreOffice dependency.

Nutrient Node.js SDK (formerly PSPDFKit): According to Nutrient's documentation, it "relies entirely on its own technology built from the ground up, and it doesn't depend on third-party tools such as LibreOffice or Microsoft Office." Handles font substitution automatically.

Apryse Server SDK: According to Apryse's guide, it converts "DOCX files to PDF using Apryse's Server SDK in Node.js without third-party dependencies." Note: it installs native binaries (system-specific distributions).

Aspose.Words for Node.js: According to Aspose's documentation, conversion is two lines: let doc = new aw.Document("input.docx"); doc.save("output.pdf");. Supports PDF/A compliance. Pricing starts at $1,199/yr per developer.

Pros: No LibreOffice. High fidelity. PDF/A compliance options. Enterprise support.

Cons: Commercial licensing ($500–$2,000+/yr). Native binaries may not fit serverless size limits. Vendor lock-in.

Option 3: Hosted APIs (no local deps)

Hosted conversion APIs accept a DOCX file via HTTP and return a PDF. Your application has zero local dependencies — the conversion happens on the provider's infrastructure.

  • ConvertAPINode.js SDK, per-document pricing, supports 200+ conversions
  • CloudConvert — REST API, 25 free conversions/day, then per-document
  • Adobe PDF Services API — 500 free transactions/month, SDKs in Node.js/.NET/Java
  • Gotenberg Cloud — hosted Gotenberg, no Docker management

Pros: Zero local dependencies. Works from any environment including serverless. No LibreOffice, no native binaries. High fidelity (most use LibreOffice or custom engines server-side).

Cons: Per-document cost. Network dependency (latency, availability). Data leaves your infrastructure — privacy/compliance concern for sensitive documents. Not suitable for high-volume batch generation (cost scales linearly with volume).

Best for: Low-to-medium volume conversion (under 10,000 documents/month), where the per-document cost is lower than the engineering cost of managing LibreOffice.

Option 4: Skip conversion — generate both from JSON

If you control the document's content (it's generated by your code, not uploaded by users), you can skip the conversion step entirely. Generate the DOCX and the PDF independently from the same source data.

import { generate as toDocx } from "@paperjsx/json-to-docx";
import { generate as toPdf } from "@paperjsx/json-to-pdf";
import { writeFileSync } from "node:fs";

const schema = {
  meta: { title: "Q3 Report", pdfua: true },
  pages: [{
    elements: [
      { type: "text", value: "Q3 Report",
        style: { fontSize: 24, bold: true } },
      { type: "table",
        headers: ["Region", "Revenue"],
        rows: [["NA", "$4,200"], ["EMEA", "$3,100"]] }
    ]
  }]
};

// Same schema → two files, no conversion step
writeFileSync("report.docx", await toDocx(schema));
writeFileSync("report.pdf", await toPdf(schema));

Pros: Zero external dependencies (pure JS, no Puppeteer, no LibreOffice). Works on every runtime including Edge Functions and Cloudflare Workers. No quality loss from format translation. PDF output can include PDF/UA accessibility. Same schema also produces PPTX and XLSX.

Cons: Cannot convert existing DOCX files — only works for new documents defined in JSON. Layout is schema-defined, not pixel-for-pixel identical to Word's rendering. Requires PaperJSX All Formats plan ($149/mo). Disclosure: PaperJSX is my product.

Best for: Applications that generate documents from database data (invoices, reports, certificates) and need both DOCX and PDF output. See the multi-format tutorial.

Decision framework

If your situation is…Use
Converting user-uploaded DOCX files to PDFLibreOffice (free) or hosted API (serverless)
Docker-based deployment, budget-consciousGotenberg (LibreOffice in Docker, HTTP API)
Enterprise, no external deps, high fidelityNutrient or Aspose.Words
Serverless / edge, low volumeHosted API (ConvertAPI, CloudConvert)
Generating new documents, need DOCX + PDFPaperJSX (no conversion step)
Need PDF/UA accessible outputPaperJSX or Aspose.Words (PDF/A)
Batch converting 10K+ existing DOCX filesLibreOffice + BullMQ queue

Why no pure-JS converter exists

DOCX rendering requires implementing Word's layout engine — a system that handles paragraph spacing rules, widow/orphan control, section breaks with independent page setups, table auto-sizing with preferred widths, floating objects with text wrapping, header/footer logic with different first-page and odd/even variants, font metric calculation for precise line breaking, and footnote/endnote placement. LibreOffice has implemented this over 20+ years. Aspose and Nutrient maintain proprietary implementations. No open-source JavaScript project has attempted this because the scope is equivalent to building a word processor.

This is different from PDF generation (where libraries like pdfmake and PaperJSX work well) because PDF generation starts from structured data — the library controls the layout. DOCX conversion starts from someone else's layout — the library must reproduce it precisely.

Try PaperJSX

Generate your first editable deck from structured JSON.