Converting a Word document (.docx) to PDF produces a fixed-layout file that looks the same on every device and cannot be accidentally edited. This guide covers five methods: Microsoft Word's built-in export, LibreOffice headless CLI, Python automation, Node.js automation, and the Google Docs API.
How to convert Word to PDF in Microsoft Word
Microsoft Word has a built-in PDF export that preserves fonts, images, hyperlinks, and the table of contents as clickable PDF links.
Windows:
- Open the .docx file in Word.
- Click File, then Save As.
- Choose PDF from the file type dropdown.
- Select "Standard (publishing online and printing)" for full quality, or "Minimum size" for a smaller file.
- Click Save.
macOS:
- Open the .docx file in Word.
- Click File, then Export to PDF (or Save As and pick PDF).
- Choose a location and click Export.
Word's export produces the most faithful PDF because it uses the same rendering engine that displays the document on screen. If your document uses custom fonts, Word embeds them automatically. This is the best option for one-off conversions when you have a Word license.
How to convert Word to PDF with LibreOffice (free, no license)
LibreOffice is a free, open-source office suite that reads .docx files and exports PDF from the command line without a GUI. It runs on Linux, macOS, and Windows.
Install LibreOffice
# macOS
brew install --cask libreoffice
# Ubuntu / Debian
sudo apt install libreoffice
# Windows (winget)
winget install LibreOfficeConvert a single file
libreoffice --headless --convert-to pdf document.docxThe --headless flag runs LibreOffice without opening a window. The output file document.pdf appears in the current directory.
Convert all .docx files in a directory
libreoffice --headless --convert-to pdf *.docxSpecify an output directory
libreoffice --headless --convert-to pdf --outdir ./pdfs *.docxLibreOffice processes each file sequentially. On a 2024 MacBook Pro (M3), a 10-page document with images converts in about 2 seconds. A 200-page report takes 8 to 12 seconds.
LibreOffice substitutes missing fonts with metrically similar alternatives. If your .docx uses a commercial font like Calibri or Cambria, install the Microsoft core fonts on Linux to avoid layout shifts. On macOS and Windows, these fonts are typically already present.
How to convert Word to PDF in Python
Python has two practical approaches: the docx2pdf library for simple conversions, and subprocess with LibreOffice for server environments.
Using docx2pdf
docx2pdf wraps Microsoft Word on Windows and macOS (via COM automation and AppleScript), and falls back to LibreOffice on Linux.
pip install docx2pdfimport docx2pdf
# Single file
docx2pdf.convert("invoice.docx", "invoice.pdf")
# All .docx files in a directory
docx2pdf.convert("./documents/", "./pdfs/")On Windows and macOS, docx2pdf produces output identical to Word's own export because it calls Word directly. On Linux, it calls LibreOffice under the hood.
Using subprocess with LibreOffice
For servers where installing Word is not an option, call LibreOffice directly:
import subprocess
from pathlib import Path
def docx_to_pdf(input_path: str, output_dir: str = ".") -> str:
"""Convert a .docx file to PDF using LibreOffice."""
subprocess.run(
["libreoffice", "--headless", "--convert-to", "pdf",
"--outdir", output_dir, input_path],
check=True,
timeout=60,
)
stem = Path(input_path).stem
return str(Path(output_dir) / f"{stem}.pdf")
pdf_path = docx_to_pdf("report.docx", "./output")
print(f"Saved: {pdf_path}")Batch convert a directory
from pathlib import Path
import subprocess
input_dir = Path("./documents")
output_dir = Path("./pdfs")
output_dir.mkdir(exist_ok=True)
docx_files = list(input_dir.glob("*.docx"))
for docx in docx_files:
subprocess.run(
["libreoffice", "--headless", "--convert-to", "pdf",
"--outdir", str(output_dir), str(docx)],
check=True,
timeout=120,
)
print(f"Converted {len(docx_files)} files")LibreOffice does not support concurrent conversions from the same installation directory. If you need parallel processing, use separate
--user-installprofiles or run conversions sequentially.
How to convert Word to PDF in Node.js
The libreoffice-convert npm package wraps the LibreOffice CLI and returns a Buffer.
npm install libreoffice-convertimport { readFileSync, writeFileSync } from "fs";
import { convert } from "libreoffice-convert";
import { promisify } from "util";
const convertAsync = promisify(convert);
async function docxToPdf(inputPath: string, outputPath: string) {
const input = readFileSync(inputPath);
const pdf = await convertAsync(input, ".pdf", undefined);
writeFileSync(outputPath, pdf);
console.log(`Saved: ${outputPath}`);
}
docxToPdf("contract.docx", "contract.pdf");This requires LibreOffice installed on the system. The library spawns a LibreOffice process per conversion, so it is best suited for low-volume or batch workloads rather than high-throughput API endpoints.
Batch conversion in Node.js
import { readdirSync } from "fs";
import path from "path";
const inputDir = "./documents";
const outputDir = "./pdfs";
const files = readdirSync(inputDir).filter((f) => f.endsWith(".docx"));
for (const file of files) {
await docxToPdf(
path.join(inputDir, file),
path.join(outputDir, file.replace(".docx", ".pdf"))
);
}
console.log(`Converted ${files.length} files`);How to convert Word to PDF with Google Docs API
The Google Docs API can import a .docx file to Google Docs format, then export it as PDF. This approach works without any local software but requires a Google Cloud project with the Drive API enabled.
from google.oauth2.service_account import Credentials
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload
import io
creds = Credentials.from_service_account_file(
"service-account.json",
scopes=["https://www.googleapis.com/auth/drive"],
)
drive = build("drive", "v3", credentials=creds)
# Upload .docx and convert to Google Docs format
file_metadata = {
"name": "report",
"mimeType": "application/vnd.google-apps.document",
}
media = MediaFileUpload("report.docx", mimetype=(
"application/vnd.openxmlformats-officedocument"
".wordprocessingml.document"
))
uploaded = drive.files().create(
body=file_metadata, media_body=media, fields="id"
).execute()
# Export as PDF
request = drive.files().export_media(
fileId=uploaded["id"], mimeType="application/pdf"
)
buffer = io.BytesIO()
downloader = MediaIoBaseDownload(buffer, request)
done = False
while not done:
_, done = downloader.next_chunk()
with open("report.pdf", "wb") as f:
f.write(buffer.getvalue())
# Clean up the temporary Google Docs file
drive.files().delete(fileId=uploaded["id"]).execute()
print("Saved: report.pdf")Google Docs handles most .docx formatting correctly, but complex features like SmartArt, embedded macros, and certain chart types may not convert.
Comparison: which method to use?
| Method | Requires Word license | Runs headless | Font fidelity | Batch support | Best for |
|---|---|---|---|---|---|
| Microsoft Word | Yes | No | Exact | No (manual) | One-off, highest fidelity |
| LibreOffice CLI | No | Yes | High (with fonts installed) | Yes | Servers, CI/CD, batch |
| Python (docx2pdf) | Windows/macOS: yes; Linux: no | Yes | Depends on backend | Yes | Scripts, mixed environments |
| Python (subprocess) | No | Yes | High (with fonts installed) | Yes | Linux servers |
| Node.js (libreoffice-convert) | No | Yes | High (with fonts installed) | Yes | Node.js backends |
| Google Docs API | No | Yes (cloud) | Good | Yes (with quota) | No local install, cloud-first |
For production systems that need the highest fidelity without a Word license, LibreOffice with the correct fonts installed is the standard choice. Microsoft Word's own export produces the most accurate PDF but requires a license and a GUI session (or COM automation on Windows).
Common formatting issues and fixes
Fonts shift or change. The number one cause of layout differences between the .docx and the PDF is missing fonts. LibreOffice and Google Docs substitute missing fonts with alternatives that have different character widths, which shifts line breaks and page breaks. Fix: install the exact fonts from the .docx on the conversion machine. On Linux, install ttf-mscorefonts-installer for Calibri, Cambria, and other Microsoft fonts.
Table columns resize. Complex tables with merged cells or auto-fit columns sometimes render with different column widths in LibreOffice. Fix: set explicit column widths in the Word document instead of relying on auto-fit. Alternatively, convert with Word on Windows via docx2pdf for exact table rendering.
Headers and footers misalign. Word and LibreOffice handle header/footer margins slightly differently. A header that sits 10mm from the top edge in Word may sit at 11mm in LibreOffice. Fix: use consistent margin values in the Word document's page setup, and verify the PDF output.
Embedded charts render differently. Word charts use the Office charting engine, which LibreOffice does not replicate exactly. Colors, axis labels, and legend positioning may shift. Fix: export charts as images in the Word document before converting, or accept minor visual differences.
File size is too large. Word documents with high-resolution images produce large PDFs. After conversion, run the PDF through the PDF4.dev compress tool to reduce the file size without visible quality loss. A typical 15 MB PDF with photos compresses to 2 to 4 MB.
When to use HTML-to-PDF instead of Word-to-PDF
Word-to-PDF conversion works well for documents authored by humans in Word. But for documents generated programmatically (invoices, receipts, reports, certificates), starting from a Word template and filling it with data is fragile. Font substitution, table resizing, and margin drift compound when you generate hundreds of documents per day.
PDF4.dev takes a different approach: you write an HTML template with CSS for pixel-exact layout, inject data via Handlebars variables, and render the PDF with a headless browser. The output is identical every time because the rendering engine (Chromium) is the same one that displays the template in the browser.
const response = await fetch("https://api.pdf4.dev/v1/render", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PDF4_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
template_id: "monthly-report",
data: {
company: "Acme Corp",
month: "March 2026",
revenue: "$142,000",
expenses: "$98,500",
},
}),
});
const pdf = await response.arrayBuffer();This produces a PDF with exact fonts, exact spacing, and zero conversion artifacts. For programmatic document generation at scale, HTML-to-PDF with PDF4.dev is more reliable than converting .docx files.
Try the free HTML to PDF toolTry it freeSummary
- For one-off conversions with a Word license, use Word's built-in File, Save As PDF. It produces the most faithful output.
- For free conversions without Word, install LibreOffice and run
libreoffice --headless --convert-to pdf document.docx. - For Python automation, use
docx2pdf(wraps Word on Windows/macOS, LibreOffice on Linux) or call LibreOffice viasubprocess. - For Node.js, use the
libreoffice-convertnpm package, which wraps LibreOffice CLI. - For cloud-only workflows, use the Google Docs API to upload and export as PDF.
- Install the exact fonts from your .docx files on the conversion machine to avoid layout shifts.
- For documents you generate programmatically, skip Word entirely: use PDF4.dev to render PDFs directly from HTML templates with exact control over fonts, layout, and data.
Start generating PDFs
Build PDF templates with a visual editor. Render them via API from any language in ~300ms.


