Getting Started
Installation
Install modern-pdf-lib with your preferred package manager:
npm install modern-pdf-libpnpm add modern-pdf-libbun add modern-pdf-libdeno add npm:modern-pdf-libNOTE
modern-pdf-lib is ESM-only. It requires Node 25.7 or later, or any runtime with native ES module support.
Supported Runtimes
| Runtime | Minimum Version | Notes |
|---|---|---|
| Node.js | 25.7+ | Full support including WASM acceleration |
| Deno | Latest | Full support via npm: specifier |
| Bun | Latest | Full support |
| Cloudflare Workers | — | Streaming output, no file system |
| Browsers | ES2024+ | All modern browsers via bundler |
Your First PDF
Create a simple "Hello World" PDF in just a few lines:
import { createPdf, PageSizes, rgb } from 'modern-pdf-lib';
const pdf = createPdf();
const page = pdf.addPage(PageSizes.A4);
page.drawText('Hello, Modern PDF!', {
x: 50,
y: 700,
size: 24,
color: rgb(0.1, 0.1, 0.1),
});
const bytes = await pdf.save();The bytes variable is a Uint8Array containing a valid PDF document.
Running in Node
Write the PDF to a file using the Node fs module:
import { writeFile } from 'node:fs/promises';
import { createPdf, PageSizes, rgb } from 'modern-pdf-lib';
const pdf = createPdf();
const page = pdf.addPage(PageSizes.A4);
page.drawText('Hello from Node!', {
x: 50,
y: 700,
size: 24,
color: rgb(0, 0, 0),
});
const bytes = await pdf.save();
await writeFile('output.pdf', bytes);
console.log('Wrote output.pdf');You can also stream the output directly to a file to reduce peak memory usage:
import { createWriteStream } from 'node:fs';
import { Writable } from 'node:stream';
const stream = pdf.saveAsStream();
const fileStream = createWriteStream('output.pdf');
await stream.pipeTo(Writable.toWeb(fileStream));Running in the Browser
In a browser context you can trigger a download or display the PDF in an iframe:
import { createPdf, PageSizes, rgb } from 'modern-pdf-lib';
const pdf = createPdf();
const page = pdf.addPage(PageSizes.A4);
page.drawText('Hello from the browser!', {
x: 50,
y: 700,
size: 24,
color: rgb(0, 0, 0),
});
const blob = await pdf.saveAsBlob();
const url = URL.createObjectURL(blob);
// Trigger a download
const a = document.createElement('a');
a.href = url;
a.download = 'document.pdf';
a.click();
// Clean up
URL.revokeObjectURL(url);Running in Cloudflare Workers
Return the PDF as a streaming HTTP response:
import { createPdf, PageSizes, rgb } from 'modern-pdf-lib';
export default {
async fetch(): Promise<Response> {
const pdf = createPdf();
const page = pdf.addPage(PageSizes.A4);
page.drawText('Hello from Workers!', {
x: 50,
y: 700,
size: 24,
color: rgb(0, 0, 0),
});
const stream = pdf.saveAsStream();
return new Response(stream, {
headers: {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename="document.pdf"',
},
});
},
};WASM Initialization
modern-pdf-lib ships with optional WebAssembly modules that accelerate compression, PNG decoding, font parsing, and text shaping. Without WASM, the library falls back to pure-JavaScript implementations.
How It Works
WASM modules are not loaded automatically — you must explicitly initialize them by passing pre-compiled WebAssembly.Module instances or by specifying which modules to load. Without WASM, the library uses pure-JS fallbacks that produce identical output.
import { initWasm } from 'modern-pdf-lib';
// Load specific WASM modules during app startup
await initWasm({ deflate: true, png: true, fonts: true });
// All subsequent operations use WASM-accelerated paths
const bytes = await pdf.save();You can also provide custom paths to the .wasm files if your deployment requires specific asset locations:
await initWasm({
deflateWasm: new URL('./wasm/deflate.wasm', import.meta.url),
pngWasm: new URL('./wasm/png.wasm', import.meta.url),
});TIP
WASM acceleration is entirely optional. The pure-JS fallback produces identical PDFs — just slightly slower for large documents.
Next Steps
- Text Drawing — Fonts, sizes, colors, and positioning
- Images — Embed PNGs and JPEGs
- Fonts — Custom fonts, subsetting, and complex scripts
- Shapes — Rectangles, circles, lines, and colors
- Streaming — Memory-efficient output for large documents
- API Reference — Full TypeDoc-generated reference