Home  ›  Guides  ›  Choosing your surface

Choosing your surface

Write application code → the library. Drive a shell, Makefile or CI job → pdfnative-cli. Give a conversational AI assistant tool access → pdfnative-mcp. Author documents inside a React 19 app → pdfnative-react. All four surfaces sit on the same zero-dependency engine and produce the same ISO 32000-1 / PDF/A-conformant bytes, so the choice is about who is calling, not about what comes out — and you can switch later without re-authoring your documents.

The decision, in prose#

You are writing application code — a Node.js, Deno, Bun or browser service, a worker, a script with logic around the PDF. Use the library (npm install pdfnative). It is the full surface: synchronous builders, the parser, signatures with long-term validation, streaming, Web Worker support. Everything the other three surfaces do, they do by calling this package.

You are driving a shell, a CI pipeline, a container, or a build tool in another language. Use the CLI (pdfnative-cli, binary pdfnative) — 21 commands over stdin/stdout pipelines, with an agent-native automation contract: a --json envelope, stable E_* error codes, --dry-run, and compact --summary / --fields output projection. No JavaScript required.

You are (or you are building) a conversational assistant with tool access — Claude Desktop, Cursor, Continue, Zed, or any Model Context Protocol client. Use the MCP server (pdfnative-mcp, npx -y pdfnative-mcp) — 28 tools with strict JSON Schemas, read-back tools for self-verification, and no outbound network access except the operator-configured TSA/OCSP/CRL endpoints.

Your host application is React 19. Use the React renderer (pdfnative-react) — declarative JSX compiled on-device to pdfnative blocks by a custom reconciler (no DOM, no headless browser), with live-preview hooks and the token-frugal DocSpec for agent authoring. React 19 is a peer dependency of this package only; the engine stays zero-dependency.

Capability × surface#

The same facts in machine-readable form live in docs/data/surfaces.json; tool, command and export names are verified against docs/assets/ecosystem.json and the engine's export surface by the documentation CI. Version annotations name the release of that surface's own package which introduced the capability; an em-dash means the surface does not offer it.

Capability Library (pdfnative) CLI (pdfnative-cli) MCP (pdfnative-mcp) React (pdfnative-react)
Generate documents buildDocumentPDFBytes / buildPDFBytes render generate_basic_pdf (+ the dedicated document tools) renderToBytes and friends, <Document> tree
Smart tables table block render (table block, or --variant table) add_table <Table>
Native vector charts chart block (v1.6.0) render (chart block) (v1.3.0) add_chart (v1.5.0) <Chart> (v1.1.0; charts v2 — nine kinds, secondary axis, log/time scales, data labels — since v1.2.0)
Digital signatures (PAdES CMS) addSignaturePlaceholder (v1.2.0) + signPdfBytes sign sign_pdf (+ prepare_signature_placeholder)
LTV ladder (B-T → B-LTA) signPdfBytesWithTimestamp, addValidationInfo, addDocumentTimestamp (v1.7.0) sign --timestamp, ltv, doc-timestamp (v1.4.0) add_ltv, timestamp_pdf (v1.6.0)
Encrypt / decrypt build-time encryption layout option; existing PDFs via the page-tree encrypt option and openPdf with a password encrypt / decrypt (v1.3.0) encrypt_pdf / decrypt_pdf (v1.5.0) build-time only, via the layout render option
Fill / flatten forms readFormFields, fillForm, flattenForm (v1.6.0) fill (v1.3.0) read_form_fields, fill_form (v1.5.0)
Extract text extractText (v1.6.0) extract-text (v1.3.0) extract_text
Merge / split / extract pages mergePdfs, splitPdf, extractPages (v1.4.0) merge / split / extract (v1.2.0) merge_pdfs / split_pdf / extract_pages (v1.3.0)
Markup annotations buildAnnotation + PdfModifier.addAnnotation (v1.5.0) annotate (v1.2.0) annotate_pdf (v1.4.0)
Inspect layout (pagination dry run) inspectDocumentLayout (v1.5.0) render --inspect-layout (v1.2.0) inspect_layout (v1.6.0) inspectDocument
Validate PDF/UA validatePdfUA (v1.3.0) inspect --pdfua (v1.1.0) validate_pdf (v1.1.0) — (lintDocument checks the authoring model before rendering, not the emitted PDF)
Update metadata (signature-safe) PdfModifier.updateMetadata (v1.7.0) metadata (v1.4.0) update_metadata (v1.6.0)
Compare two PDFs (text + structure) — (compose openPdf / extractText / the readers) compare (v1.4.0)
Runtime font registration registerFont / registerFonts (v1.5.0, any loader — incl. fonts you compile with compileFontData) render --font (bundled fonts only) (v1.1.0) — (fixed lang enum; fonts resolved from the local pdfnative install) registerFont / registerFonts (re-exported)

Honest notes#

You can switch later#

All four surfaces call the same engine, so the artefacts are interchangeable: a PDF rendered by the React reconciler can be signed by the CLI, inspected by an MCP tool, and have its text extracted by the library. Document inputs travel too — the CLI's render consumes the same DocumentParams JSON the library takes, the MCP generate_basic_pdf blocks mirror the engine's block kinds, and pdfnative-react compiles JSX (or a DocSpec) into that same model. Starting on the "wrong" surface costs a call-site migration, not a document rewrite.

Further reading#