Pure Native PDF Generation
Zero dependencies. ISO 32000-1 compliant. 22 Unicode scripts with BiDi and OpenType shaping. TypeScript-first.
npm install pdfnative
Zero dependencies. ISO 32000-1 compliant. 22 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, Telugu, Sinhala, Tibetan, Khmer, Myanmar, Amharic, CJK, Cyrillic, Greek, Devanagari, and more. Full UAX #9 BiDi — isolates + explicit embeddings (LRE/RLE/LRO/RLO/PDF). OpenType GSUB/GPOS shaping for Thai, Arabic, Devanagari, Bengali, Tamil, Telugu, Sinhala, Tibetan, Khmer, and Myanmar.
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. One-call placeholder injection via addSignaturePlaceholder(). 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. Smart tables: multi-page slicing with repeated headers, auto-wrap, zebra striping, captions, and per-cell borders. Document tools: bookmarks (/Outlines), page labels, viewer preferences, nested lists, and a merge / split / extract page-tree API. Tables guide → · Manipulation guide →
AsyncGenerator streaming (including object-boundary page-by-page), Web Worker off-thread generation, PDF parser & modifier. 2 379+ tests across 104 files, 95%+ statement coverage, SLSA provenance.
Use pdfnative from Claude Desktop, Cursor, Continue, Zed, and any other stdio MCP client (Cline, Windsurf, Goose, Gemini CLI…) via pdfnative-mcp. 19 production tools incl. page-tree merge_pdfs / split_pdf / extract_pages, markup annotate_pdf, the network-free draft_governance_issue, validate_pdf, verify_pdf, add_attachment / extract_attachments, extract_text, pdfA flag everywhere, and token-frugal read modes. Zero configuration beyond npx -y pdfnative-mcp.
Render, sign, inspect & verify PDFs from the terminal with pdfnative-cli. End-to-end signing pipeline (RSA + ECDSA-SHA256), real CMS/PKCS#7 verify with RFC 3161 detection, render --watch / --template / --font, batch & completion commands, automatic signature-placeholder injection. Read the CLI guide → · Try the playground →
Author PDFs declaratively in JSX with pdfnative-react. A custom React reconciler compiles <Document> / <Table> / <Barcode> trees on-device — no DOM, no headless browser. Live-preview hooks (usePdf, <PDFViewer>), streaming, and a token-frugal DocSpec for AI agents. React is a peer dependency of this package only. React guide → · Try the playground →
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
});
Pick an example, edit the code, then click "Generate PDF" — it runs entirely in your browser via the npm CDN.
Need more? Browse all 44 generator categories (~227 sample PDFs) on GitHub.
Four adoption paths — pick the one that fits your stack. All four are zero-config and zero-build.
For TypeScript / JavaScript apps.
npm install pdfnative
import { buildDocumentPDFBytes, extractText } from 'pdfnative';
const pdf = buildDocumentPDFBytes({
title: 'Hello',
blocks: [{ type: 'paragraph', text: 'Hello, world.' }],
});
extractText(pdf)[0].text; // 'Hello, world.' — parse any PDF back
Quick Start guide →
For shells, CI, and Makefiles.
echo '{"blocks":[{"type":"paragraph","text":"Hi"}]}' \
| npx pdfnative-cli render -o out.pdf
# Sign and verify (RSA or ECDSA)
npx pdfnative-cli sign -i out.pdf -o signed.pdf \
--key key.pem --cert cert.pem
npx pdfnative-cli verify -i signed.pdf
CLI guide →
For Claude Desktop, Cursor, Continue, Zed, …
{
"mcpServers": {
"pdfnative": {
"command": "npx",
"args": ["-y", "pdfnative-mcp"]
}
}
}
Drop into your MCP client config — the full tool set becomes available instantly.
MCP guide →For React, Next.js, and Remix apps.
npm install pdfnative-react pdfnative react
import { Document, Heading, renderToBytes } from 'pdfnative-react';
const pdf = renderToBytes(
<Document title="Hello">
<Heading level={1}>Hello, world.</Heading>
</Document>,
);
React guide →
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 | 22 | 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.
Measured locally with vitest bench on an Intel Core i3 mini-PC (Node.js 22) — mean wall-clock time per document. Faster hardware (Apple M-series, desktop i7/i9) typically runs 2–4× quicker. Results may vary.
Run npx vitest bench to measure on your hardware.
No carbon claims, no offsets, no badges. Just architectural choices that keep the runtime small, local, and verifiable from the source tree.
PDFs are assembled in the calling process — Node, browser, Worker, Deno, Bun. No SaaS round-trip; no document leaves the user's machine unless the application chooses to send it.
An empty dependencies field in package.json. No transitive npm graph to install, audit, or patch.
The library never opens a socket. Verifiable by reading the source — there is no analytics endpoint, no auto-update channel, no remote font fetch.
"sideEffects": false with strict module boundaries. Only the features your build actually imports end up in production bundles.
streamPdf() yields Uint8Array chunks via AsyncGenerator, so even very large documents fit in bounded memory on edge runtimes and serverless platforms.
The optional veraPDF reference validator runs as a CI tool, downloaded once per workflow run. It is never bundled with the npm package or required by consumers.
pdfnative is built with AI coding agents — and it governs them. A machine-readable contract and a human-in-the-loop protocol keep agents in a draftsman role: they may propose, but a human always reviews, approves, and submits. Nothing reaches GitHub autonomously.
Read the full protocol in the AI governance guide, or inspect the source of truth: .github/AGENT_RULES.md and .github/ai-governance.json.
pdfnative-mcp is a Model Context Protocol server that exposes the full pdfnative library to Claude Desktop, Cursor, Continue, Zed, and any other MCP-compatible AI client. One npx command, no code required. Now with page-tree merge_pdfs / split_pdf / extract_pages, markup annotate_pdf, the network-free draft_governance_issue, validate_pdf, verify_pdf, add_attachment / extract_attachments, extract_text, a pdfA flag on every document tool, multi-script lang, and token-frugal read modes.
| Tool | Purpose |
|---|---|
generate_basic_pdf | Multi-page documents (headings, paragraphs, lists). Optional pdfA flag. |
add_table | Tabular reports — now with optional autoFitColumns and clipCells (pdfnative v1.1 TableBlock). |
add_barcode | QR Code, Code 128, EAN-13, Data Matrix, PDF417 |
add_international_text | 22 scripts with BiDi & OpenType shaping. lang now accepts string, string[], or comma-separated — e.g. ["ar", "emoji"]. |
add_form | Interactive AcroForm fields |
embed_image | JPEG / PNG image embedding |
prepare_signature_placeholder | PDF with /Sig field ready to sign |
sign_pdf | CMS/PKCS#7 signatures (RSA & ECDSA) |
inspect_pdf | Read-only inspection — version, page count, encryption, PDF/A claim, signatures, info dict; optional CI-style check: ('pdfa'|'signed'|'encrypted')[]. |
validate_pdf | Read-only PDF/UA structural validation (valid, errors, warnings). |
verify_pdf | Real CMS/PKCS#7 signature verification — RSA & ECDSA, digest, certificate chain, RFC 3161 timestamp detection (v1.0.0). |
add_attachment | Embed files (Factur-X / ZUGFeRD e-invoice XML) into PDF/A-3b output (v1.0.0). |
extract_attachments | Extract embedded files from existing PDFs (metadata-only mode available, v1.2.0). |
extract_text | Extract text content from an existing PDF via the native parser (v1.0.0). |
merge_pdfs | Concatenate 2–50 PDFs into one via the page-tree API (v1.3.0). |
split_pdf | Split one PDF into one document per page range — multi-output (v1.3.0). |
extract_pages | Pull an arbitrary, order-preserving page subset (max 5000) into a new PDF (v1.3.0). |
annotate_pdf | Overlay markup annotations (highlight / underline / note / shape) on an existing PDF via incremental update. A visual review layer, not a redaction (v1.4.0). |
draft_governance_issue | Assemble a governance-compliant GitHub-issue draft locally — network-free by construction; never submits (v1.4.0). |
{
"mcpServers": {
"pdfnative": {
"command": "npx",
"args": ["-y", "pdfnative-mcp"]
}
}
}
Supports Cursor, Continue, Zed, and any stdio MCP client. See the MCP Integration Guide → · Try the MCP playground →
pdfnative-cli is the official command-line interface. Eleven commands, zero extra runtime dependencies, stdin/stdout pipelines, NPM-provenance signed. It completes the digital-signature story with end-to-end signing (RSA + ECDSA-SHA256, native constant-time crypto), full CMS/PKCS#7 verification, RFC 3161 timestamp detection, a fast render --watch / --template / --font math / --outline loop, page-tree merge / split / extract, markup annotate, an AI-governance govern gate, plus batch and shell completion commands.
| Command | Purpose |
|---|---|
render | JSON → PDF with hybrid flags + --layout. --watch (re-render on change), --template <file.json> (deep-merge base), --font {latin,emoji,math}, --outline auto (bookmarks), --inspect-layout / --debug-layout. |
sign | End-to-end CMS/PKCS#7 signing. ECDSA-SHA256 fully wired, native constant-time node:crypto by default (--pure-crypto opts out). Auto-injects the AcroForm signature placeholder when missing. |
inspect | Read-only PDF analysis. --verbose, --pages, --annotations, page labels, and --check pdfa|signed|encrypted|pdfua for CI assertions. |
verify | Real CMS/PKCS#7 verification — signature value (RSA + ECDSA-SHA256), message digest, certificate chain, trust roots, RFC 3161 timestamp token detection. JSON report. |
merge v1.2 | Concatenate 2–50 PDFs into one via the page-tree API. |
split v1.2 | Split one PDF into many — one output per page or per range. |
extract v1.2 | Pull a selected, order-preserving page subset into a single PDF. |
annotate v1.2 | Attach markup annotations via an incremental save — signatures stay valid. |
govern v1.2 | Surface the AI-governance / HITL contract — rules, policy, verify-issue. |
batch | Render many JSON inputs to PDFs in one invocation — glob input, parallelism, per-file status. |
completion | Generate shell completion scripts (bash / zsh / fish). |
# Render → sign → verify, end-to-end
echo '{"blocks":[{"type":"paragraph","text":"Hello, signed world."}]}' \
| npx pdfnative-cli render -o out.pdf
npx pdfnative-cli sign -i out.pdf -o signed.pdf \
--algorithm ecdsa-sha256 \
--key key.pem --cert cert.pem --reason "Approved"
npx pdfnative-cli verify -i signed.pdf --strict
Keys, certs, and encryption passwords are read from env vars (PDFNATIVE_SIGN_KEY, PDFNATIVE_ENCRYPT_OWNER_PASS…) and never logged. See the CLI guide → · Try the CLI builder →
pdfnative-react is the official React renderer. A custom React reconciler compiles your JSX component tree — synchronously, with no DOM and no headless browser — into pdfnative blocks, then renders real ISO 32000-1 / PDF/A bytes on-device. React 19 is a peer dependency of pdfnative-react only — the core engine stays zero-dependency.
| Surface | What you get |
|---|---|
<Document> / <Page> | Document metadata, page size, headers/footers, tagged & PDF/A modes. |
| Content | <Heading>, <Text>, <List>/<Item>, <Table>/<Row>/<Cell>, <Image>, <Link>, <Barcode>, <Svg>, <FormField>, <Toc>. |
| Render | renderToBytes / renderToBlob / renderToStream / renderToFile — plus compileDocument for the raw params. |
| Live preview | usePdf / usePdfStream hooks & client components <PDFViewer>, <PDFDownloadLink>, <BlobProvider>. |
| Agent-friendly | Token-frugal DocSpec (compileSpec/renderSpec*) with a published JSON Schema for LLM authoring. |
npm install pdfnative-react pdfnative react
import { Document, Heading, Text, Table, renderToBytes } from 'pdfnative-react';
const bytes = renderToBytes(
<Document title="Invoice #1024" footerText="Acme Inc">
<Heading level={1}>Invoice #1024</Heading>
<Text>Thank you for your business.</Text>
<Table headers={['Item', 'Total']} rows={[{ cells: ['Pro plan', '$49.00'] }]} zebra />
</Document>,
); // → Uint8Array, a valid PDF
Compiles on-device — no SaaS round-trip, no Chromium. See the React guide → · Try the React playground →
The code that became pdfnative was originally built inside plika.app — a personal finance application requiring multi-language PDF bank statements across many Unicode 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.