Zero dependencies. ISO 32000-1 compliant. 16 Unicode scripts with BiDi and OpenType shaping. TypeScript-first.
npm install pdfnative
Production-grade PDF generation with no compromises. Every feature built from scratch.
Built from scratch in pure TypeScript — tree-shakeable, auditable, and free from supply-chain risk. Even the crypto is built in.
Thai, Arabic, Hebrew, Bengali, Tamil, CJK, Cyrillic, Greek, Devanagari, and more. Full BiDi layout (UAX #9). OpenType GSUB/GPOS shaping for Thai, Arabic, Devanagari, Bengali, and Tamil.
PDF 1.7 (ISO 32000-1), PDF/A-1b/2b/2u/3b (ISO 19005), PDF/UA tagged accessibility. Structure tree, XMP metadata, ICC profiles.
AES-128/256 encryption with granular permissions. CMS/PKCS#7 digital signatures — RSA and ECDSA P-256. Zero external crypto deps.
12 block types: tables, images, barcodes (5 ISO formats), SVG, AcroForm fields, TOC, watermarks, hyperlinks. Pure PDF vector ops — no rasterization.
AsyncGenerator streaming, Web Worker off-thread generation, PDF parser & modifier. 1 563+ tests, 95%+ coverage, SLSA provenance.
Two builders for every use case — table-centric financial reports or free-form documents.
import { buildPDFBytes, downloadBlob } from 'pdfnative';
const pdf = buildPDFBytes({
title: 'Monthly Report',
infoItems: [
{ label: 'Period', value: 'January 2026' },
{ label: 'Account', value: 'Main Account' },
],
balanceText: 'Balance: $1,234.56',
countText: '42 transactions',
headers: ['Date', 'Description', 'Category', 'Amount', 'Status'],
rows: [
{ cells: ['01/15', 'Grocery Store', 'Food', '-$45.00', ''],
type: 'debit', pointed: false },
{ cells: ['01/16', 'Salary', 'Income', '+$3,000.00', 'X'],
type: 'credit', pointed: true },
],
footerText: 'Generated by MyApp',
});
downloadBlob(pdf, 'report.pdf');
import { buildDocumentPDFBytes } from 'pdfnative';
const pdf = buildDocumentPDFBytes({
title: 'Project Report',
blocks: [
{ type: 'toc' },
{ type: 'heading', text: 'Executive Summary', level: 1 },
{ type: 'paragraph', text: 'This quarter saw strong growth...' },
{ type: 'image', data: chartBytes, width: 400,
align: 'center', alt: 'Revenue chart' },
{ type: 'list', style: 'bullet',
items: ['Revenue up 15%', 'Costs down 8%', 'Net profit +23%'] },
{ type: 'barcode', format: 'qr', data: 'https://example.com',
width: 80, ecLevel: 'M' },
{ type: 'svg', content: svgString, width: 300 },
{ type: 'formField', fieldType: 'text', name: 'notes',
label: 'Notes', width: 400 },
],
footerText: 'Confidential',
tagged: 'pdfa2b', // PDF/A-2b compliance
compress: true, // FlateDecode compression
});
import { registerFonts, loadFontData, buildDocumentPDFBytes }
from 'pdfnative';
// Register lazy-loaded Noto Sans font data modules
registerFonts({
th: () => import('pdfnative/fonts/noto-thai-data.js'),
ar: () => import('pdfnative/fonts/noto-arabic-data.js'),
bn: () => import('pdfnative/fonts/noto-bengali-data.js'),
ja: () => import('pdfnative/fonts/noto-jp-data.js'),
});
// Load only the scripts you need
const fonts = await Promise.all(
['th', 'ar', 'bn', 'ja'].map(loadFontData)
);
const fontEntries = fonts.filter(Boolean).map((fd, i) => ({
fontData: fd!, fontRef: `/F${3 + i}`,
lang: ['th', 'ar', 'bn', 'ja'][i],
}));
const pdf = buildDocumentPDFBytes({
title: 'Multi-Language Document',
blocks: [
{ type: 'heading', text: 'สวัสดี — مرحبا — こんにちは', level: 1 },
{ type: 'paragraph',
text: 'pdfnative renders Thai, Arabic (with BiDi), Bengali, ' +
'and Japanese — all from a single API call.' },
],
fontEntries,
tagged: true, // PDF/A-2b with structure tree
});
Edit the code below, then click "Generate PDF" — it runs entirely in your browser.
Feature-by-feature comparison with popular PDF libraries.
| Feature | pdfnative | pdfkit | jsPDF | pdfmake | pdf-lib |
|---|---|---|---|---|---|
| Runtime dependencies | 0 | 6 | 3 | 3 | 4 |
| TypeScript native | ✓ | @types | ✓ | @types | ✓ |
| Unicode scripts | 16 | Via fontkit | Custom fonts | Via pdfkit | Via @pdf-lib/fontkit |
| BiDi (Arabic / Hebrew) | ✓ | ✗ | ✗ | ✗ | ✗ |
| PDF/A compliance | 4 levels | ✗ | ✗ | ✗ | ✗ |
| AES encryption | 128 + 256 | ✓ | ✓ | ✓ | ✗ |
| Digital signatures | RSA + ECDSA | ✗ | ✗ | ✗ | ✗ |
| Barcodes / QR codes | 5 formats | ✗ | ✗ | QR | ✗ |
| SVG rendering | ✓ | ✓ | Plugin | ✓ | Paths only |
| Interactive forms | ✓ | ✓ | ✓ | ✗ | ✓ |
| Streaming output | ✓ | ✓ | ✗ | ✓ | ✗ |
| PDF parser / modifier | ✓ | ✗ | ✗ | ✗ | ✓ |
| Browser + Node.js | ✓ | Via bundler | ✓ | ✓ | ✓ |
| Tree-shakeable | ✓ | ✗ | ✗ | ✗ | ✓ |
Pure string assembly with zero allocations in hot paths. Measured with vitest bench.
Benchmarks run on Node.js 22, Apple M-series / Intel i7. Results may vary.
Run npx vitest bench to measure on your hardware.
The code that became pdfnative was originally built inside plika.app — a personal finance application requiring multi-language PDF bank statements across 16 scripts.
Rather than depending on heavy third-party libraries, the PDF engine was written from scratch with zero dependencies, strict ISO compliance, and native Unicode shaping. It was then extracted and open-sourced as an independent library for everyone.