Engineering

The Developer's Guide to PDF Engines: Browser vs. Native Rendering

A technical comparison of browser-based PDF generation (Puppeteer, wkhtmltopdf) vs native engines (Typst, Cairo). Learn the trade-offs for your architecture.

Typcraft TeamTypcraft Team
7 min read
Browser vs Native PDF Engine Architecture Diagram
#pdf-generation#architecture#puppeteer#typst

When you need to generate PDFs programmatically, you have a fundamental architectural choice: browser-based rendering or native document engines.

This isn't a "which product should I buy" comparison. It's a technical deep-dive into two different philosophies for turning data into documents. Understanding the trade-offs will help you make the right choice for your system.

The Two Philosophies#

Browser-based rendering treats PDF generation as a side effect of web rendering. You create HTML, load it in a headless browser, and export the rendered page as a PDF.

Native rendering uses purpose-built document engines that understand PDF as a first-class output format. You describe your document in a markup language or API, and the engine compiles directly to PDF primitives.

Neither approach is inherently "better." They optimize for different constraints.

How Browser-Based Engines Work#

The Pipeline#

  1. Launch headless browser: Start a Chromium, Firefox, or WebKit instance
  2. Load content: Navigate to a URL or inject HTML directly
  3. Render the page: Apply CSS, execute JavaScript, layout the DOM
  4. Export to PDF: Capture the rendered page using the browser's print-to-PDF functionality

Puppeteer is the most widely used browser automation library. It controls headless Chromium and provides a clean API for PDF generation:

JavaScript
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(htmlContent);
const pdf = await page.pdf({ format: 'A4' });
await browser.close();

Playwright offers similar functionality with multi-browser support (Chromium, Firefox, WebKit). It's newer and has better TypeScript support.

wkhtmltopdf uses an older Qt WebKit engine. It's a standalone binary without the Node.js dependency, but its CSS support is stuck in 2012.

Architectural Characteristics#

AspectBrowser-Based
Memory per request200-500MB (full browser process)
Cold start2-5 seconds (loading browser binary)
ConcurrencyLimited by RAM; each request needs its own process
CSS supportExcellent (current browser engine)
JavaScriptFull support; SPAs work
Learning curveLow if you know HTML/CSS

Where Browser-Based Shines#

  • Existing HTML templates: If you've already invested in web-based document design
  • JavaScript-heavy documents: Charts, interactive elements, client-side rendering
  • Exact web parity: When the PDF must look identical to the web page
  • Rapid prototyping: CSS is familiar; iteration is fast

Where Browser-Based Struggles#

  • High volume: Memory and CPU overhead limits throughput
  • Serverless: Large binary size causes cold starts
  • Consistency: Rendering varies across browser versions and platforms
  • Print-specific features: Page numbers, headers, footers require workarounds

How Native Engines Work#

The Pipeline#

  1. Parse document source: Read a markup language (Typst, LaTeX, ReportLab API)
  2. Layout calculation: Compute positions, handle pagination natively
  3. Render to PDF primitives: Write directly to PDF format (text, vectors, images)

Typst is a modern document formatting system written in Rust. It compiles to PDF in milliseconds and is designed for embedding:

TYPST
#set page(paper: "a4")
#set text(font: "Linux Libertine")
 
= Invoice \#2026-001
 
#table(
  columns: (1fr, auto, auto),
  [*Item*], [*Qty*], [*Price*],
  [Pro Plan], [1], [\$29.00],
)
 
*Total:* \$29.00

LaTeX/pdfTeX is the academic standard. Powerful but complex syntax, slower compilation, harder to embed in applications.

Cairo is a low-level 2D graphics library used by many PDF generators. It's not a document engine—you draw shapes and text manually.

ReportLab (Python) provides a programmatic API for PDF construction. Good for code-first document generation.

Prawn (Ruby) is similar to ReportLab—a code-based PDF builder.

Architectural Characteristics#

AspectNative Engine (Typst)
Memory per request20-100MB (no browser)
Cold start< 100ms (small binary)
ConcurrencyHigh; CPU-bound, not memory-bound
CSS supportNone (different paradigm)
JavaScriptNone (documents are declarative)
Learning curveMedium (new syntax to learn)

Where Native Engines Shine#

  • High volume: Generate thousands of documents per minute
  • Serverless: Small binaries, instant cold starts
  • Consistency: Same input always produces identical output
  • Typography: Native support for proper kerning, ligatures, fonts
  • Print features: Page numbers, headers, footers are first-class

Where Native Engines Struggle#

  • Existing HTML templates: No direct migration path
  • Team familiarity: Requires learning a new markup language
  • Dynamic content: JavaScript-based rendering isn't possible
  • Web preview: Matching web and PDF output requires separate templates

Performance Comparison#

These benchmarks are representative, not absolute. Your results will vary based on document complexity, server specs, and implementation details.

Single-Page Document#

EngineGeneration TimeMemory
Puppeteer800ms - 2s250MB
wkhtmltopdf500ms - 1.5s150MB
Typst15 - 50ms30MB
LaTeX200ms - 1s100MB

100-Page Document#

EngineGeneration TimeMemory
Puppeteer15 - 40s500MB+
wkhtmltopdf10 - 30s300MB
Typst1 - 3s80MB
LaTeX5 - 15s200MB

Scaling Characteristics#

Browser-based engines scale linearly with memory. Each concurrent request needs its own browser process. At 500MB per request, a 4GB server handles ~8 concurrent generations.

Native engines are CPU-bound. They can share memory and scale with CPU cores. The same 4GB server might handle 50+ concurrent Typst compilations.

When to Choose Each#

Choose Browser-Based When:#

  • You have existing HTML/CSS templates that work well
  • Your team's strength is web development
  • You need to render JavaScript-based content (charts, SPAs)
  • Volume is low (under 1,000 documents/month)
  • Documents are simple (1-5 pages, basic layouts)
  • Exact web-to-PDF parity is required

Choose Native When:#

  • You're building a new document system from scratch
  • Volume is high (10,000+ documents/month)
  • Serverless deployment is important
  • Consistent output across environments is critical
  • Documents are long or complex (50+ pages)
  • Typography and print quality matter

The Hybrid Approach#

Some systems use both:

  • Browser for preview: Designers work in familiar HTML/CSS
  • Native for production: Server generates PDFs with native engine
  • Sync layer: Template changes update both representations

This gives you the best of both worlds: familiar editing and fast generation. The cost is maintaining two rendering paths.

Migration Considerations#

From Browser-Based to Native#

  1. Audit your templates: Categorize by complexity and usage
  2. Prototype high-volume documents first: These benefit most from migration
  3. Accept visual differences: Native output won't be pixel-identical to browser output
  4. Plan for parallel operation: Run both systems during transition

Template Portability#

There's no automatic converter from HTML to Typst or LaTeX. Migration means recreating templates in the new format.

For simple documents (invoices, receipts), this takes hours. For complex documents (reports with charts, custom layouts), it takes days.

API Migration#

If you're switching PDF libraries, your API calls change:

JavaScript
// Browser-based (Puppeteer)
const pdf = await page.pdf({ format: 'A4' });
 
// Native (Typst CLI)
const pdf = execSync('typst compile template.typ --format pdf');
 
// Native (Typst as library via API)
const pdf = await typcraft.generate({
  templateId: 'invoice',
  data: invoiceData
});

The abstraction level differs. Browser-based APIs control a browser. Native APIs compile documents.

Making Your Decision#

Ask yourself these questions:

  1. What's your volume? Under 1,000/month, browser-based is fine. Over 10,000/month, native pays off.

  2. What's your deployment target? Serverless favors native (smaller cold starts). Dedicated servers can run either.

  3. What are your team's skills? HTML/CSS expertise favors browser-based. Willingness to learn new tools favors native.

  4. How complex are your documents? Simple documents work anywhere. Complex, long documents stress browser-based engines.

  5. How important is consistency? If byte-identical output matters, native engines are more reliable.

Proof of Concept Approach#

Don't commit based on theory. Test with your actual documents:

  1. Pick your most problematic document (the one that's slow, inconsistent, or breaks)
  2. Recreate it in a native engine
  3. Benchmark both approaches with your real data
  4. Compare output quality, not just speed

The right choice depends on your specific constraints. But now you understand the trade-offs.


Want to try native PDF generation? Typcraft uses Typst under the hood. Generate your first document free.

Typcraft Team

Written by

Typcraft Team

Building the next generation of document automation.

@typcraftapp

Continue Reading