Blog

gPdf vs Puppeteer: Wann 800 MB Chromium die falsche Antwort sind

Puppeteer rendert jede Webseite zu PDF, aber Sie bezahlen für einen Headless Browser, den Sie meistens gar nicht nutzen. Ein pragmatischer Vergleich für Entwickler, die 2026 einen PDF-Stack auswählen.

Wenn Sie heute nach “Puppeteer PDF Alternative” gesucht haben und hier gelandet sind, lautet Ihre eigentliche Frage vermutlich in etwa:

“Warum braucht meine serverlose Funktion 2 Sekunden Cold Start und 900 MB RAM, nur um eine Rechnung zu drucken?”

Puppeteer ist ein hervorragendes Werkzeug. Es ist aber auch massiv überdimensioniert für die Aufgabe, für die viele Teams es einsetzen: strukturierte Daten in ein vorhersagbares PDF verwandeln. Dieser Beitrag richtet sich an Teams, die kurz davor sind, Puppeteer in Produktion zu bringen, und sich leise fragen, ob es eine vernünftigere Option gibt.

Wir gehen durch, wo Puppeteer sein Gewicht verdient, wo nicht, und wie die echte Trade-off-Matrix 2026 aussieht.

Was Sie mit Puppeteer tatsächlich ausliefern

Wenn Sie npm install puppeteer ausführen, laden Sie vor den transitiven Abhängigkeiten bereits einen etwa 170 MB großen Chromium-Build herunter. Zur Laufzeit braucht Headless Chromium für einen einzelnen Page Render 600 bis 900 MB resident memory und 1 bis 2 Sekunden Cold-Start-Zeit, um den Browser zu starten. Jeder Render muss:

  1. den Browserprozess booten oder einen Pool wiederverwenden,
  2. einen neuen Tab öffnen,
  3. zu Ihrem HTML oder Ihrer URL navigieren,
  4. auf domcontentloaded warten, meistens auch auf Fonts, Bilder und Web Components,
  5. page.pdf() ausführen, wodurch die gemalte Seite durch Chromiums PDF-Engine serialisiert wird,
  6. den Tab schließen.

Das ist die Steuer der gesamten Webplattform. Sie bezahlen sie unabhängig davon, ob Ihr Dokument ein 90-seitiger Rechtsvertrag mit eingebetteten SVG-Charts oder ein einseitiges Versandlabel mit fünf Textzeilen ist.

Für HTML-zu-PDF-Fälle, in denen Ihre Eingabe wirklich CSS-Layout, JavaScript-getriebene Inhalte, Web Fonts und den Rest der Webplattform braucht, ist diese Steuer fair. Für alles andere - Rechnungen, Labels, Belege, Tickets, Statements, Zertifikate - verbrennen Sie damit Geld.

Wo Puppeteer gewinnt

Das sollte zuerst ehrlich geklärt werden, sonst wird Ihr Team die Entscheidung später infrage stellen:

  • Treues HTML/CSS-Rendering. Wenn Ihr Designsystem HTML ausgibt und Sie pixelidentische PDFs dieses HTML wollen, ist Puppeteer kaum zu schlagen. Es ist buchstäblich Chrome beim Drucken.
  • Webplattform-Features. SVG mit Filtern, CSS-Grid-Randfälle, Web Components, durch JavaScript ausgewertete Inhalte, Drittanbieter-iframes: alles funktioniert.
  • Visuelles Debugging. Sie können während des Renderns einen Screenshot machen, DevTools gegen den Headless Mode öffnen und genau sehen, was der Renderer sieht.
  • Kein Übersetzungsschritt. Wenn Ihr Inhalt bereits eine Webseite ist, gibt es kein Schema-Mapping. page.goto(url); await page.pdf() ist die gesamte Pipeline.

Wenn zwei dieser Punkte Ihre echte Last beschreiben, wechseln Sie nicht. Puppeteer ist die richtige Antwort.

Wo Puppeteer deutlich verliert

Für alles andere wächst der Kostenstapel schnell.

Speicher und Cold Start in serverlosen Umgebungen

Eine typische Node-20-Lambda oder ein Cloudflare Container mit Puppeteer:

Metrik Typischer Wert
Container-Image-Größe 250 bis 400 MB (Chromium + Node + Ihr Code)
Cold-Start-Zeit 1,8 bis 2,5 Sekunden
Warm RAM pro Render 600 bis 900 MB
Gleichzeitige Renders pro 1-GB-Instanz 1, manchmal 2 bei sehr kleinen Seiten

Wenn Ihr Rechnungsservice 100.000 Renders pro Monat verarbeitet, bezahlen Sie bei jedem kalten Container Browser-Bootup, obwohl keiner dieser Renders JavaScript-Ausführung brauchte.

Die “Fonts im Container”-Falle

Chromium bringt ein Standard-Font-Set mit, dem meist CJK, Kyrillisch, Devanagari, Arabisch und viele skriptspezifische Glyphen fehlen. In Produktion sieht die Entdeckung so aus:

Die Q3-2025-Rechnung für das Büro in Tokio druckt ▢▢▢▢ 2025年第3四半期. Der Kunde eskaliert. Ihr Team verbringt einen Sprint mit Dockerfile-Font-Installationen und Font-Fallback-CSS.

Allein NotoSans CJK einzubetten, fügt Ihrem Image etwa 50 MB hinzu. Ein globales Noto-Fallback-Set fügt etwa 250 MB hinzu. Sie bezahlen für Chromium und eine Font-Kathedrale, nur um eine japanische Rechnung zu drucken.

Determinismus

Puppeteer-Renders sind über Chromium-Versionen hinweg nicht byte-identisch. Ein Patch-Upgrade kann Kerning, Font-Baselines oder Seitenumbruchpositionen subtil verschieben. Wenn Sie eine Testsuite haben, die PDFs diffed, und das sollten Sie, wird jedes Chromium-Update zu einer kleinen archäologischen Untersuchung: Was hat sich geändert, und war es beabsichtigt?

JavaScript zur Renderzeit

Selbst Ihre “statische” HTML-Seite muss geparst, layouted, gemalt und serialisiert werden. Empirisch sind das 80 bis 400 ms pro Seite auf einem warmen Prozess. Der Großteil davon ist Layout, nicht Paint.

Zum Vergleich: Ein Server, der JSON direkt an einen Binary Renderer gibt, braucht für dieselbe einseitige Rechnung 3 bis 8 ms.

Wo gPdf passt

gPdf dreht das Modell um: Sie beschreiben Ihr Dokument nicht als HTML und bitten einen Browser, es zu malen. Sie beschreiben es als strukturiertes JSON (DocumentRequest), und ein Rust-Renderer, der zu WebAssembly kompiliert ist, gibt das PDF direkt aus. Es gibt keinen Browser, kein DOM und keinen JavaScript-Layout-Pass.

Das klingt einschränkend, und für HTML-förmige Probleme ist es das auch. Für die Dokumentklassen Rechnung / Label / Beleg / Statement / Zertifikat passt das JSON-first-Modell aber besser:

  • Ihre Daten sind bereits strukturiert. Eine Rechnung lebt meist irgendwo als { customer, lines, totals, taxes, notes }-Objekt. Sie wollen sie nicht erst zu HTML rendern, damit ein Browser das HTML wieder als Layout liest. Sie wollen direkt von Daten zu PDF.
  • Layout wird zum Vertrag. Wenn font_size: 11 immer 11 Punkte bedeutet und gap: 8 immer 8 Punkte bedeutet, sehen zwei Entwickler im PR-Review exakt dieselbe Ausgabe. Es gibt keine Interpretationslücke bei display: flex.
  • Die Ausgabe ist byte-identisch. Gleiche Eingabe → gleiche Bytes. Sie können zwei PDFs mit git diff vergleichen und sehen nur echte Änderungen.
  • Cold Start ist Runtime-Start, nicht Browser-Boot. Ein V8 isolate auf Cloudflare Workers initialisiert in 5 bis 20 ms. Das WASM-Modul bleibt im selben isolate über Aufrufe hinweg warm.

Ein typischer gPdf-Render einer einseitigen Rechnung liegt am Edge bei 3 bis 5 ms p50 Wall Clock, bedient aus dem Cloudflare-Colo, den der Nutzer trifft. Das ist ungefähr zwei Größenordnungen schneller als Puppeteers warmer Pfad und drei Größenordnungen schneller als sein kalter Pfad.

Die Entscheidungsmatrix

Nutzen Sie die Tabelle, die Sie in einem echten Tech-Design-Review verwenden würden.

Workload Puppeteer nutzen gPdf nutzen
Bestehender HTML-Report → PDF ✅ erste Wahl ⚠️ erfordert Rewrite
Rechnungen, Statements, Belege ⚠️ schwerer Hammer ✅ erste Wahl
Versandlabel mit Barcodes ❌ vermeiden (Font-Probleme) ✅ erste Wahl
E-Rechnung (Factur-X / ZUGFeRD / EN 16931) ❌ kein integrierter Support ✅ integriert
PDF/A-Langzeitarchivierung ⚠️ braucht Ghostscript-Pass ✅ integrierte Profile
Pixelgenaue Designsystem-Mockups ✅ erste Wahl ❌ falsches Werkzeug
Charts, die echtes D3 / Recharts brauchen ✅ erste Wahl ❌ falsches Werkzeug
Tickets, Zertifikate, Namensschilder ⚠️ Overkill ✅ erste Wahl
Alles, was JavaScript zur Renderzeit braucht ✅ einzige Wahl ❌ falsches Werkzeug

Wenn Sie in mehr als drei dieser Zeilen in der rechten Spalte landen, sind die Einsparungen nicht subtil.

Echter Vergleich: Render einer einseitigen Rechnung

Gleicher Inhalt. Gleiches Papierformat. Gleiche Fonts (NotoSans). Gleiches Ausgabeprofil PDF/A-3b.

Puppeteer (warme Lambda, 1 GB) gPdf (warmer Cloudflare Worker)
p50-Latenz 180 ms 3,4 ms
p99-Latenz 420 ms 8 ms
Cold-Start-Aufschlag +1800 ms beim ersten Render +12 ms beim ersten Render
Peak-Speicher 720 MB 18 MB
Image-/Modulgröße 280 MB 4,5 MB
CJK-Glyphen ❌ nur mit expliziter Installation ✅ NotoSans CJK eingebettet
Kosten / 100.000 Renders ca. 240 USD (Lambda Compute) ca. 5 USD (gPdf Basic Plan)

Die letzte Zeile überrascht viele. Die Kostenlücke ist real und kein Lockangebot. Wir müssen keinen Chromium-Boot, keinen Browser-Speicher und keine Container-Cold-Starts amortisieren, also sind die Stückkosten pro Render wirklich winzig.

“Aber 5 USD pro 100.000 Seiten klingt zu günstig. Wo ist der Haken?”

Der Haken ist genau, dass wir keinen Browser ausliefern. Ein Binary Renderer auf einem warmen V8 isolate kostet Millisekunden CPU und Kilobytes Speicher. Puppeteer-förmige Preise dafür zu verlangen, hieße für Infrastruktur zu berechnen, die wir nicht betreiben.

Wann Sie trotzdem Puppeteer wählen sollten

Wir wären die falsche Adresse, wenn unsere Antwort immer “gPdf nutzen” wäre. Ist sie nicht. Die ehrlichen Fälle:

  1. Sie betreiben Puppeteer bereits in Produktion und es funktioniert. Migrieren Sie nicht aus Sport. Der richtige Zeitpunkt, gPdf zu prüfen, ist dann, wenn Puppeteer weh tut: meist wenn die monatlichen Compute-Rechnungen über 400 USD steigen oder Cold-Start-SLAs downstream etwas brechen.

  2. Ihre Dokumente sind bestehende Webseiten, Punkt. Ein 60-seitiger benutzergenerierter Report, gestylt durch Ihr Designsystem, mit verschachtelten Charts und dynamischen Inhalten, ist keine JSON-Migration. Es ist ein Redesign.

  3. Sie brauchen pixelgenaue Parität mit einer Web-Preview. Manche Workflows, etwa “was Sie im Editor sehen, ist das, was gedruckt wird”, brauchen Chromium wirklich als Renderer an beiden Stellen.

Wenn keiner dieser Punkte zutrifft, ist die Rechnung klar: kleineres Deployment, niedrigere Latenz, niedrigere Rechnung, byte-identische Ausgabe und kein Font-Installationsdrama.

Wie Sie einen echten Workload migrieren

Wenn Sie überzeugt genug sind, es zu testen, ist die Migration meistens ein Spike von 1 bis 2 Tagen pro Dokumenttyp, keine Re-Architektur:

  1. Wählen Sie ein Dokument, am besten das mit dem höchsten Volumen, nicht das komplexeste.
  2. Mappen Sie die logischen Abschnitte Ihrer HTML-Vorlage auf gPdf JSON-Elemente (text, box, table, barcode, image).
  3. Iterieren Sie im Playground mit einem echten DocumentRequest, bis die Ausgabe passt.
  4. Verdrahten Sie Ihre bestehende Datenform mit einer kleinen Mapper-Funktion, die JSON ausgibt.
  5. Testen Sie den neuen Endpoint eine Woche per A/B gegen Ihren Puppeteer-Endpoint. Vergleichen Sie die PDFs. Entscheiden Sie.

Die meisten Teams finden innerhalb eines Tages in das JSON-Modell. Der schwierige Teil ist nicht das neue Werkzeug, sondern die HTML/CSS-Gymnastik zu entwirren, die in der alten Vorlage über die Zeit gewachsen ist.

TL;DR

Puppeteer ist die richtige Antwort für Webseiten. Für Dokumente zahlen Sie bei jedem Render eine 100- bis 200-fache Steuer, um die kleine einmalige Arbeit zu vermeiden, Ihr Dokument als Daten zu beschreiben. Wenn Ihre Flotte Rechnungen, Labels, Belege, Statements, Tickets oder alles andere rendert, das “immer dieselbe Form, nur andere Werte” hat, ist ein Edge-nativer Renderer wie gPdf messbar schneller, kleiner, günstiger und deterministischer.

Testen Sie es im Playground: ein echter Edge Worker, kein Signup, Antwort in Ihrem Browser in unter 5 ms.