Skip to content

Getting Started

ABCrimson edited this page Mar 1, 2026 · 5 revisions

Getting Started

modern-pdf-lib is a WASM-accelerated PDF creation engine for JavaScript. It runs in Node.js, Deno, Bun, Cloudflare Workers, and modern browsers — with a single unified ESM API across all runtimes.

Note: modern-pdf-lib is ESM + CJS dual format. Works with both import and require(). Node.js 25.7 or later is required.


Table of Contents


Installation

Install with your preferred package manager:

Package Manager Command
npm npm install modern-pdf-lib
pnpm pnpm add modern-pdf-lib
Bun bun add modern-pdf-lib
Deno deno add npm:modern-pdf-lib

All exports are available from the top-level package import:

import { createPdf, PageSizes, rgb } from 'modern-pdf-lib';

Your First PDF

Five lines to a working PDF:

import { createPdf, PageSizes, rgb } from 'modern-pdf-lib';

const pdf  = createPdf();
const page = pdf.addPage(PageSizes.A4);

page.drawText('Hello, World!', { x: 72, y: 720, size: 36, color: rgb(0, 0, 0) });

const bytes = await pdf.save(); // Uint8Array

That's it. bytes is a fully valid PDF file you can write to disk, send over the network, or turn into a Blob.


Runtime Examples

Node.js — File Write

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.js', { x: 72, y: 720, size: 24, color: rgb(0, 0, 0) });

const bytes = await pdf.save();
await writeFile('output.pdf', bytes);

console.log('Saved output.pdf');

Node.js — Streaming

Use saveAsStream() when you want to pipe a large PDF directly into an HTTP response or a file stream without buffering the entire document in memory.

import { createWriteStream } from 'node:fs';
import { Writable } from 'node:stream';
import { createPdf, PageSizes, rgb } from 'modern-pdf-lib';

const pdf  = createPdf();
const page = pdf.addPage(PageSizes.A4);

page.drawText('Streamed PDF', { x: 72, y: 720, size: 24, color: rgb(0.2, 0.4, 0.8) });

const readable = pdf.saveAsStream(); // ReadableStream (Web Streams API)
const dest     = createWriteStream('streamed-output.pdf');

await readable.pipeTo(Writable.toWeb(dest));

console.log('Streamed to streamed-output.pdf');

Tip: saveAsStream() returns a standard Web Streams API ReadableStream, so it works identically across Node.js 25.7+, Deno, and browsers.


Browser — Blob Download

import { createPdf, PageSizes, rgb } from 'modern-pdf-lib';

async function downloadPdf() {
  const pdf  = createPdf();
  const page = pdf.addPage(PageSizes.A4);

  page.drawText('Hello from the Browser', { x: 72, y: 720, size: 24, color: rgb(0, 0, 0) });

  const blob = await pdf.saveAsBlob(); // Blob with MIME type 'application/pdf'
  const url  = URL.createObjectURL(blob);

  const anchor      = document.createElement('a');
  anchor.href       = url;
  anchor.download   = 'document.pdf';
  anchor.click();

  URL.revokeObjectURL(url);
}

Note: saveAsBlob() is only available in browser environments. Calling it in Node.js or a Worker runtime will throw an error. Use save() or saveAsStream() in those environments instead.


Cloudflare Workers — Streaming Response

import { createPdf, PageSizes, rgb } from 'modern-pdf-lib';

export default {
  async fetch(request) {
    const pdf  = createPdf();
    const page = pdf.addPage(PageSizes.A4);

    page.drawText('Generated by Cloudflare Workers', {
      x: 72,
      y: 720,
      size: 20,
      color: rgb(0.1, 0.1, 0.1),
    });

    const stream = pdf.saveAsStream();

    return new Response(stream, {
      headers: {
        'Content-Type':        'application/pdf',
        'Content-Disposition': 'attachment; filename="worker-output.pdf"',
      },
    });
  },
};

Tip: Streaming with saveAsStream() avoids materializing the full PDF buffer in the Worker's limited memory — prefer it over save() for large documents.


Deno

import { createPdf, PageSizes, rgb } from 'npm:modern-pdf-lib';

const pdf  = createPdf();
const page = pdf.addPage(PageSizes.A4);

page.drawText('Hello from Deno', { x: 72, y: 720, size: 24, color: rgb(0, 0.5, 0.8) });

const bytes = await pdf.save();
await Deno.writeFile('output.pdf', bytes);

console.log('Saved output.pdf');

WASM Initialization

modern-pdf-lib ships with an optional WebAssembly module that accelerates:

  • Font subsetting — dramatically reduces file size for embedded fonts
  • Text shaping — correct glyph ordering for complex scripts (Arabic, Indic, etc.)

Auto Mode (recommended)

By default, the library initializes the WASM module automatically on first use. No configuration is required for most projects.

// WASM is loaded lazily — no setup needed
const pdf  = createPdf();
const page = pdf.addPage(PageSizes.A4);

page.drawText('WASM kicks in automatically', { x: 72, y: 720, size: 18 });

const bytes = await pdf.save();

Explicit Initialization

If you need fine-grained control — for example, to pre-warm the WASM engine during application startup or to supply a custom .wasm URL — use initWasm():

import { initWasm, createPdf, PageSizes, rgb } from 'modern-pdf-lib';

// Call once, before any PDF operations.
// Resolves when the WASM module is fully loaded and compiled.
await initWasm({
  // Optional: override the default .wasm asset URL.
  // Useful when self-hosting assets or enforcing a CDN policy.
  wasmUrl: 'https://your-cdn.example.com/modern-pdf-lib/modern-pdf-lib.wasm',
});

const pdf  = createPdf();
const page = pdf.addPage(PageSizes.A4);

page.drawText('WASM is ready', { x: 72, y: 720, size: 24, color: rgb(0, 0.6, 0.2) });

const bytes = await pdf.save();

Note: Calling initWasm() more than once is safe — subsequent calls resolve immediately using the already-loaded module.

Mode How to use When to choose
Auto Just import and call createPdf() Most projects — simple, zero config
Explicit await initWasm() before first use App startup pre-warming, custom CDN, test isolation

Next Steps

Once you have a basic document working, explore the rest of the library:

Topic Wiki Page
Annotations Annotations
Fonts & text Font Subsetting
WASM acceleration WASM Acceleration
Forms (AcroForms) Forms
PDF merging & splitting Merge and Split
Encryption Security
Accessibility (PDF/UA) Accessibility
Digital signatures Security
Architecture Architecture

modern-pdf-lib v0.15.1 — ESM + CJS — Node 25.7+ / Deno / Bun / Cloudflare Workers / Browser

Clone this wiki locally