ADR-012: PuppeteerSharp — HTML to PDF Rendering
Date: 2026-02-28 Authors: Jean-Francois Meyers Scope: granit-dotnet (Granit.DocumentGeneration.Pdf)
Context
Section titled “Context”The Granit.DocumentGeneration.Pdf module converts HTML (generated by Scriban)
into PDF documents. Use cases include: invoices, medical reports, certificates,
and regulatory documents.
Requirements:
- CSS fidelity: pixel-perfect HTML/CSS rendering (flexbox, grid, @media print)
- PDF/A-3b: compliance for long-term archiving (ISO 27001) and Factur-X
- Headers/footers: dynamic headers and footers (pagination, date)
- Performance: generation in < 2 seconds for a standard document
Decision
Section titled “Decision”PuppeteerSharp (headless Chromium) for HTML to PDF conversion.
Alternatives considered
Section titled “Alternatives considered”Option 1: PuppeteerSharp (selected)
Section titled “Option 1: PuppeteerSharp (selected)”- License: MIT
- Advantage: perfect CSS fidelity (Chromium Blink engine), PDF/A-3b support (via post-processing), dynamic headers/footers, landscape/portrait, configurable margins, native async .NET API
- Pipeline: Scriban -> HTML -> PuppeteerSharp -> PDF
Option 2: QuestPDF
Section titled “Option 2: QuestPDF”- License: Community License (free < $1M revenue, otherwise commercial)
- Advantage: fluent C# API (code-first), no Chromium, lightweight
- Disadvantage: no HTML rendering (C# API only — incompatible with the Scriban -> HTML pipeline), restrictive license for enterprises, no native PDF/A, learning curve for non-developers
Option 3: iText7
Section titled “Option 3: iText7”- License: AGPL-3.0 (commercial use requires a paid license)
- Advantage: reference library for PDF manipulation, native PDF/A, very mature
- Disadvantage: AGPL license incompatible with a distributed framework (source code publication obligation), expensive commercial license, limited HTML rendering (pdfHTML paid add-on)
Option 4: wkhtmltopdf
Section titled “Option 4: wkhtmltopdf”- Advantage: lightweight, WebKit rendering
- Disadvantage: abandoned project (last release 2020), obsolete WebKit engine (no flexbox, grid), uncorrected security issues, no native .NET support (CLI wrapper)
Option 5: Playwright (via Microsoft.Playwright)
Section titled “Option 5: Playwright (via Microsoft.Playwright)”- License: Apache-2.0
- Advantage: Chromium engine like PuppeteerSharp, modern API, maintained by Microsoft
- Disadvantage: much heavier package (~200 MB vs ~50 MB — includes Firefox and WebKit), testing-oriented (no native PDF generation API, requires workarounds), higher initialization overhead
Justification
Section titled “Justification”| Criterion | PuppeteerSharp | QuestPDF | iText7 | wkhtmltopdf | Playwright |
|---|---|---|---|---|---|
| License | MIT | Freemium | AGPL/Commercial | MIT | Apache-2.0 |
| HTML rendering | Chromium (perfect) | No (C# only) | Limited (paid) | WebKit (obsolete) | Chromium |
| Scriban->HTML pipeline | Yes | No | Partial | Yes | Yes |
| PDF/A-3b | Post-processing | No | Native | No | Post-processing |
| Package size | ~50 MB | ~5 MB | ~10 MB | ~40 MB | ~200 MB |
| Maintenance | Active | Active | Active | Abandoned | Active (MS) |
| Performance | Good | Excellent | Good | Medium | Good |
Consequences
Section titled “Consequences”Positive
Section titled “Positive”- Perfect CSS fidelity: PDF is identical to browser rendering
- Unified pipeline: Scriban (template) -> HTML -> PuppeteerSharp (PDF)
- PDF/A-3b support via post-processing for ISO 27001 archiving and Factur-X
- MIT: no license constraints
- Native async .NET API with Chromium lifecycle management
Negative
Section titled “Negative”- Chromium dependency: ~50 MB binary to download on first launch
- Memory consumption: one Chromium process per rendering instance (browser pool recommended)
- Chromium startup time: ~1-2 seconds on first call (mitigated by browser pool)
- Chromium requires system dependencies in CI/production (libgbm, libatk, etc. — handled via Docker image)