REFERENCE

API reference

Define a document, register resources, and request output. All dimensions use PDF points: 72 points equal one inch.

createPdf(definition)#

TypeScript
import pdf, { createPdf } from 'minkpdf';
import type { TDocumentDefinitions } from 'minkpdf/interfaces';
import type { PdfDocument } from 'minkpdf/core';

// Signature: createPdf(definition: TDocumentDefinitions): PdfDocument
const document = createPdf({ content: 'Hello' });
const bytes = await document.getBuffer();

The root default object and named exports share one engine with the historical tables, images, and TrueType capabilities. New factories are selected explicitly through core. createPdf() accepts one document definition and returns a PdfDocument. Rendering begins on the first output request; later requests reuse the same rendered PDF.

Output methods#

MethodReturn typeUse it for
getBuffer()Promise<Uint8Array>Files, HTTP responses, and binary storage
getBlob()Promise<Blob>Browser downloads; MIME type application/pdf
getBase64()Promise<string>Base64 without a data URL prefix
getDataUrl()Promise<string>data:application/pdf;base64,…
getStream()Promise<ReadableStream<Uint8Array>>Buffered by default; optional streaming() provides incremental serialization
print(target?)Promise<void>Browser PDF viewer with a print OpenAction; optional preopened Window

The byte/Blob output methods take no arguments and share one cached render. print(target?: Window | null) is browser-only and separately caches a printable render. Rendering errors reject their promises. With streaming(), the first incremental getStream() consumes that document once; later stream or buffered-output requests reject. Requesting buffered output first retains cached output behavior. Standalone browser and Node adapters provide downloads, opening, and file writing. The default stream uses the cached buffer; optional streaming() serializes incrementally with consumer backpressure.

JavaScript
button.addEventListener('click', async () => {
  const target = window.open('', '_blank');
  if (!target) throw new Error('Print window blocked');
  await pdf.createPdf(definition).print(target);
});

Call print() directly from a user gesture, or pass a window opened during that gesture before fetching report data. With no target, MinkPDF opens a window synchronously before rendering. The promise resolves after navigation to the printable PDF, not after the user prints. Automatic printing depends on the PDF viewer honoring the print OpenAction. Object URLs are released on an afterprint event or when the target closes. A blocked popup or closed target rejects; a window created by MinkPDF closes on failure. Ordinary output methods never include a print action.

createPdfEngine(options)#

JavaScript
import { createPdfEngine } from 'minkpdf/core';
import { tables } from 'minkpdf/tables';
import { images } from 'minkpdf/images';
import { trueTypeFonts } from 'minkpdf/truetype';

const pdf = createPdfEngine({
  features: [tables(), images(), trueTypeFonts()]
});

Signature: createPdfEngine(options?: { features?: readonly PdfFeature[], validation?: 'error' | 'warn' | 'off', onDiagnostic?: (diagnostic: Diagnostic) => void }): PdfEngine. The default is core only. Every engine has independent font dictionaries, virtual files, custom table layouts, and parsed-font caches. Register resources on the engine that creates the document.

Features are fixed at construction; duplicate descriptors throw immediately. Core includes text, Helvetica variants, stacks, columns, pagination, headers/footers, metadata, watermarks, and canvas lines.

createPdfEngine({ features?, validation?, onDiagnostic? }) creates an independent resource registry. Validation defaults to 'error'; 'warn' reports ordinary unsupported properties to onDiagnostic(diagnostic) and 'off' disables those diagnostics. These modes do not bypass mandatory security checks, invalid geometry, missing fonts, or unavailable renderers. Rendering callbacks are validated when evaluated; pagination callbacks should be pure because they may run again.

Select advanced report semantics#

The historical root does not include every implemented capability. Use explicit factories for advanced documents; each content factory still needs to be selected when used. This JavaScript example needs no font files because its text is ASCII.

JavaScript
import { createPdfEngine } from 'minkpdf/core';
import { reports } from 'minkpdf/reports';
import { lists } from 'minkpdf/lists';
import { qr } from 'minkpdf/qr';

const pdf = createPdfEngine({ features: [reports(), lists(), qr()] });
const document = pdf.createPdf({
  content: [
    { text: 'Report', id: 'summary', outline: true },
    { ul: ['First item', 'Second item'] },
    { text: 'Back to summary', linkToDestination: 'summary' },
    { qr: 'https://example.com', fit: 100 }
  ]
});
const bytes = await document.getBuffer();
CapabilitySetup and limits
Typography and navigationreports() enables justification, style extends, decoration arrays and paint options, superscript/subscript, inline backgrounds, links, IDs, outlines, page/text references, and background callbacks.
Pagination and sectionsThe report backend adds named paper sizes, automatic page height, sections, and bounded dynamic page-break reflow. toc() adds generated contents; columns() adds fixed-height, equal-width snaking columns.
Vector contentSelect graphics(), svg(), or qr(). SVG excludes CSS paint servers, scripts, external resources, and advanced clipping/text transforms; QR supports Model 2 versions 1–40.
Fonts and patternsstandardFonts() adds standard font encodings; shaping() adds selected Latin GSUB/GPOS operations, not bidi or Arabic/Indic shaping. patterns() accepts uncolored PDF tiling-pattern streams with tint colors.
Files and encryptionattachments({vfs}) embeds explicit payloads; encryption() supports R6 AES-256 only. Password normalization and viewer-enforced permissions have documented limits.
Conformance and taggingarchival() supports PDF/A-2b and PDF/A-3b with embedded fonts and compatible settings. PDF/UA-1 additionally requires tagged(), subset: "PDF/UA", tagged: true, title, and language. Encryption and print actions conflict with archival output. Automated fixture validation does not replace manual accessibility review.

See the feature compatibility guide for exact profile limits, setup requirements, and unsupported combinations. Document types describe the combined API; selecting a type alone does not enable a feature.

Browser and Node output adapters#

HelperResult and behavior
downloadPdf(document, filename?)Promise<void>; browser download with temporary URL cleanup; default filename document.pdf.
openPdf(document, target?)Promise<Window>; reserve a popup in a click handler or pass a preopened window. Keeps its PDF URL until that window closes.
writePdf(document, filename)Promise<void>; Node file output after buffering. Rendering failures leave an existing destination untouched; this is not an atomic filesystem-write guarantee.
bufferedPdfStream(document)Promise<Readable>; Node stream over the complete cached buffer. It does not stream rendering.
JavaScript · Node.js
import pdf from 'minkpdf';
import { writePdf } from 'minkpdf/node';

await writePdf(pdf.createPdf({ content: 'Receipt' }), 'receipt.pdf');
JavaScript · browser
import pdf from 'minkpdf';
import { downloadPdf, openPdf } from 'minkpdf/browser-output';

const document = pdf.createPdf({ content: 'Receipt' });
// Run the chosen operation from your click handler:
// await downloadPdf(document, 'receipt.pdf');
// await openPdf(document);

Import minkpdf/node only in Node.js code. Browser adapters buffer output; openPdf() and print() need popup permission and do not wait for a user to finish viewing or printing.

Incremental PDF serialization#

JavaScript
import { createPdfEngine } from 'minkpdf/core';
import { streaming } from 'minkpdf/streaming';

const document = createPdfEngine({ features: [streaming()] })
  .createPdf({ content: 'Streamed report' });
const reader = (await document.getStream()).getReader();
let totalBytes = 0;
for (;;) {
  const { done, value } = await reader.read();
  if (done) break;
  totalBytes += value.length;
  // Send each value to your destination; avoid accumulating all chunks.
}
console.log(totalBytes);

Choose streaming() before creating the document. Call getStream() once and consume that stream, respecting destination backpressure. Starting incremental serialization makes later buffered-output and stream requests reject; requesting a buffer first uses normal cached output instead. Cancellation stops serialization. Layout, fonts, and resources still consume memory, so streaming does not make the whole rendering process constant-memory.

Document definition#

PropertyType / behavior
content requiredContent: string, number, content node, or array of content
pageSize'A4' | 'LETTER' | 'LEGAL' | { width, height }; default A4
pageOrientation'portrait' | 'landscape'; default portrait
pageMarginsMargins; default 40 points on every side
defaultStyleStyle applied throughout the document
stylesRecord<string, Style> for named styles
infoOptional title, author, subject, keywords, creator strings
header, footerContent or (page, total, size) => Content; page numbers are one-based
watermarkString or { text, color?, opacity?, bold?, italics?, fontSize?, angle? }

Margins is a number for all sides, [horizontal, vertical], or [left, top, right, bottom]. A Size is a number, 'auto', '*', or a percentage string such as '30%'.

Text and styles#

JavaScript
const definition = {
  styles: {
    title: { fontSize: 20, bold: true, color: '#d94248' },
    muted: { color: '#667085' }
  },
  content: [
    { text: 'Sales report', style: 'title', margin: [0, 0, 0, 12] },
    { text: ['Total: ', { text: 'USD 100.00', bold: true }] },
    { text: 'Prepared today', style: ['muted'], italics: true }
  ]
};
Style fieldsAccepted values
font, fontSizeRegistered family name (default Helvetica); size in points (default 12)
bold, italicsBooleans selecting font variants
color, fillColorThree- or six-digit hex colors and case-insensitive CSS named colors, e.g. #eee, red, or lightgray
alignment'left' | 'center' | 'right'
lineHeightNumeric line-height multiplier
characterSpacingAdditional spacing in points
noWrapBoolean preventing text wrapping
marginMargins
marginLeft, marginTop, marginRight, marginBottomPer-side margins in points; negative values are supported
decoration'underline' | 'lineThrough' | 'overline'
fillOpacityNumeric opacity for fills

Named styles resolve in array order; node properties override them. Margins and cell fills from named styles apply to the styled node without leaking into children. Per-side margins override the corresponding named-style sides. An explicit node margin takes precedence over its per-side properties.

Positioned content#

JavaScript
const definition = {
  pageMargins: 0,
  content: [
    { text: 'INV-001', absolutePosition: { x: 300, y: 30 } },
    { text: 'Customer', absolutePosition: { x: 40, y: 90 } },
    { text: 'Offset label', relativePosition: { x: 20, y: -10 } },
    'Normal flow continues at the original cursor'
  ]
};

absolutePosition: { x, y } anchors content to the top-left of the current page, independent of page margins and enclosing columns or cells. Text wraps within the remaining page width; explicit column widths and noWrap remain available for preprinted forms. relativePosition: { x, y } offsets the current flow cursor. Both use points, ignore their own margins, and leave the flow cursor unchanged. Positioned content stays on the current page; it is not automatically paginated and should fit inside that page.

Stacks and columns#

An array of content acts as a vertical stack. Use stack for an explicitly styled container or columns for side-by-side content, with optional columnGap and per-column width.

JavaScript
const definition = {
  content: [{
    columns: [
      { width: '*', stack: ['Customer', { text: 'Ada Lovelace', bold: true }] },
      { width: 120, text: 'Invoice 001', alignment: 'right' }
    ],
    columnGap: 16
  }]
};

Use pageBreak: 'before' | 'after' for explicit breaks and unbreakable: true for grouped content. Oversized content still needs to fit the page’s available area.

Tables#

JavaScript
import pdf from 'minkpdf';

const report = pdf.createPdf({
  pageMargins: [40, 40, 40, 60],
  defaultStyle: { fontSize: 10 },
  footer: (page, total) => ({
    text: 'Page ' + page + ' of ' + total,
    alignment: 'center', fontSize: 8, margin: [0, 12, 0, 0]
  }),
  content: [{
    table: {
      headerRows: 1,
      dontBreakRows: true,
      widths: ['*', 100],
      body: [
        [{ text: 'Item', bold: true }, { text: 'Amount', bold: true }],
        ...Array.from({ length: 100 }, (_, i) => [
          'Item ' + (i + 1), { text: '123.45', alignment: 'right' }
        ])
      ]
    }
  }]
});
Table propertyBehavior
bodyRequired array of rows; cells are strings or content nodes
widthsSize[] for fixed, automatic, star, or percentage widths
headerRowsNumber of first rows repeated when a table spans pages
keepWithHeaderRowsNumber of body rows kept with the header
dontBreakRowsKeep fitting rows together across page boundaries
heightsNumber, number array, or (row) => number

Cells support nested content, fillColor, fillOpacity, border: [left, top, right, bottom], colSpan, and rowSpan. Supply empty placeholder cells for every covered position, including later rows. Row and column spans can be combined. Merged fills and borders cover the full cell, and its content is drawn once. Connected row spans stay together when they fit; oversized groups split with their borders and fills. Spans must stay within the table and cannot cross the repeated-header boundary.

JavaScript
const definition = {
  content: { table: {
    widths: [80, '*', '*'],
    body: [
      [{ text: 'Name', rowSpan: 2 }, 'GARCÍA', 'JOSÉ'],
      [{}, 'Last name', 'First name'],
      [{ text: 'Address', colSpan: 3 }, {}, {}]
    ]
  } }
};

A table node’s layout can be a named layout or a CustomTableLayout. Register named layouts with addTableLayouts(dictionary). The historical root provides noBorders. Selecting tables() also provides headerLineOnly and lightHorizontalLines, cell verticalAlignment (top, middle, bottom), tableAlignment, and per-side borderColor. Other named layouts require registration.

JavaScript
pdf.addTableLayouts({
  compact: {
    hLineWidth: (index, node) => index === 0 ? 0 : 0.5,
    vLineWidth: () => 0,
    hLineColor: () => '#ddd',
    paddingTop: () => 3,
    paddingBottom: () => 3
  }
});
// Use layout: 'compact' alongside table: { body: ... }.

Custom layouts also accept vLineColor, paddingLeft, paddingRight, fillColor(row, node, column) returning a supported color or null, and defaultBorder. Other line/padding callbacks receive (index, node).

Fonts and resources#

Engine memberSignature and behavior
addVirtualFileSystem(vfs)(Record<string, string | Uint8Array>) => void. Merge base64 strings (without data URL prefixes) or byte arrays. Replacing a file invalidates its parsed-font cache.
addFonts(dictionary)(TFontDictionary) => void. Merge registered font families.
fontsTFontDictionary. Assigning a new dictionary replaces its contents; existing references preserve their identity.
addTableLayouts(dictionary)(Record<string, CustomTableLayout>) => void. Merge named table layouts.
JavaScript
pdf.addVirtualFileSystem({ 'Inter-Regular.ttf': fontBytes });
pdf.addFonts({ Inter: { normal: 'Inter-Regular.ttf' } });

// Replacement, rather than merging:
pdf.fonts = { Inter: { normal: 'Inter-Regular.ttf' } };

Font dictionaries map family names to { normal, bold?, italics?, bolditalics? }, with filenames pointing to registered virtual files. Embedded fonts must include the requested characters. Resources are shared among documents created by the same engine. MinkPDF does not fetch files automatically.

Font registration requires trueTypeFonts(); custom table-layout registration requires tables(). Both are already enabled by the root import. See the complete Unicode example.

Prepare resources with an explicit loader#

prepareDocumentResources(document, { loader? }) resolves named images to inline PNG/JPEG data URLs. prepareFontResources(sources, { loader? }) returns { fonts, vfs }; install both on an engine with trueTypeFonts(). Sources may be bytes, base64 data URLs, or URL/path strings and { url, headers? } addresses. External sources require a caller-supplied loader returning Promise<Uint8Array>; font VFS registration separately accepts raw base64 strings.

JavaScript
import { prepareDocumentResources } from 'minkpdf/resources';

const definition = await prepareDocumentResources({
  images: { logo: '/assets/logo.png' },
  content: [{ image: 'logo', width: 80 }]
}, {
  loader: async (url, options) => {
    const response = await fetch(url, options);
    if (!response.ok) throw new Error('Image request failed');
    return new Uint8Array(await response.arrayBuffer());
  }
});
// Pass definition to the root or an engine with images() selected.

Loaders own credentials, redirects, and access policy. The helpers perform no implicit network or filesystem access and do not install resources globally. Optional images() prepares named inline sources automatically; prepare external sources yourself with a loader before rendering.

Images#

The image node accepts a PNG or JPEG base64 data URL. Use width, height, or fit: [width, height] to size it. Add images() to a core engine, and tables() if placing images in table cells.

JavaScript
import pdf from 'minkpdf';

const logo = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==';
const document = pdf.createPdf({
  content: [{ image: logo, fit: [40, 40] }, 'Receipt']
});

PNG support includes non-interlaced 8-bit grayscale, RGB, indexed, grayscale-alpha, and RGBA images with transparency. The root accepts inline data URLs. Optional images() additionally supports named resources and cover: { width, height, align?, valign? } cropping; height-only sizing preserves aspect ratio. Prepare URL/file sources with the resource helper above. Select svg() for SVG nodes; it is not a PNG/JPEG image format.

Pages, headers, and decorations#

JavaScript
const definition = {
  pageSize: 'A4',
  pageOrientation: 'portrait',
  pageMargins: [40, 60, 40, 60],
  info: { title: 'Draft report', author: 'Finance team' },
  header: { text: 'Monthly report', margin: [40, 20, 0, 0] },
  footer: (page, total, size) => ({
    text: 'Page ' + page + ' of ' + total,
    alignment: 'center', fontSize: 8, margin: [0, 12, 0, 0]
  }),
  watermark: { text: 'DRAFT', opacity: 0.15, color: '#d94248' },
  content: [
    'Summary',
    { canvas: [{ type: 'line', x1: 0, y1: 8, x2: 240, y2: 8,
                lineWidth: 0.5, lineColor: '#ddd' }] },
    { text: 'Details', pageBreak: 'before' }
  ]
};

Header/footer callbacks receive the final total page count and size: { width, height, orientation }. Reserve sufficient top and bottom margins for them. The historical root canvas supports lines. The optional graphics() feature adds shapes, fills, strokes, dashes, and clipping.

Errors and supported limits#

JavaScript
try {
  const bytes = await pdf.createPdf(definition).getBuffer();
  // Store or send the PDF bytes.
} catch (error) {
  console.error('PDF generation failed:', error);
}

Missing capabilities, unregistered fonts or variants, invalid colors, and margins that leave no content area produce errors. Duplicate feature descriptors and resource registration on disabled capabilities throw synchronously; render failures reject output promises.

SVG, QR codes, lists, attachments, encryption, and PDF/A are available through optional factories with explicit limits. See the feature compatibility guide for setup and supported profiles. Full complex-script shaping is unsupported. The optional PDF/UA-1 profile has automated corpus validation; reading order and alternate-text quality require human evaluation. CSS color functions such as rgb(), eight-digit hex colors, transparent, and currentColor are unsupported; use fillOpacity or watermark opacity for transparency. See the pdfmake comparison for migration limits and public interface definitions for the complete types.

Search pages, examples, and API methods.