DEV Community

elements
elements

Posted on

We replaced Chromium with a 1MB HTML-to-PDF library for Azure Functions

Most document-generation infrastructure starts the same way:

HTML template in, headless browser, PDF out.

It is a rational default. Browsers are excellent CSS renderers, and no engineering team wants to fund a layout engine just to print invoices.

But defaults chosen during prototyping can become production liabilities.

That is the problem I wanted to evaluate with Bhowra.Ink, a Chromium-free HTML-to-PDF renderer for .NET.

The question was simple:

For static business documents, do we really need to ship a full browser just to generate a PDF?

This post is a technical evaluation of that question.


The cost profile of a browser in your PDF pipeline

When a headless browser is used only as a print engine, the cost shows up in four places.


1. Deployment weight

A browser-based PDF pipeline usually brings hundreds of megabytes of browser binaries into the deployment.

That is not just an aesthetic problem.

It affects:

  • build time
  • container size
  • registry storage
  • rollout speed
  • cold starts
  • vulnerability scanning

For a service whose job is to render static invoice HTML, that can feel like too much machinery.


2. Latency

A browser process has to start before the first byte of PDF exists.

On long-running servers, that may be acceptable.

On serverless platforms, cold starts are part of the operating model.

If PDF generation needs to run inside Azure Functions, AWS Lambda, or short-lived containers, process startup time matters.


3. Memory

A browser is designed to render the web.

That includes JavaScript, layout, painting, networking, fonts, images, security isolation, and many browser APIs.

For full web-page rendering, that is exactly what you want.

For static invoices, statements, payslips, and reports, it may be unnecessary overhead.


4. Security ownership

If Chromium is in your production pipeline, Chromium becomes part of your operational responsibility.

That means:

  • browser CVEs
  • patch cycles
  • dependency scanning
  • sandbox behavior
  • container hardening
  • runtime compatibility

For some applications, that trade-off is worth it.

For static business documents, I wanted to understand whether a smaller rendering stack could be enough.


To be clear: browsers are still the right tool sometimes

This is not an argument against browser-based rendering as a category.

Use Playwright, Puppeteer, or Chromium if your document needs:

  • JavaScript execution
  • SPA rendering
  • browser APIs
  • canvas output
  • client-side chart libraries
  • screenshot-like fidelity of a real web page

That is what browsers are good at.

But many enterprise PDFs are not web apps.

They are static, server-rendered documents:

  • invoices
  • receipts
  • statements
  • payslips
  • reports
  • contracts
  • certificates
  • labels

For those documents, a full browser can be overkill.


The alternative I evaluated

I wanted to look at a PDF pipeline that behaves like a normal .NET library.

dotnet add package Bhowra.Ink
Enter fullscreen mode Exit fullscreen mode

Then:

using Bhowra.Ink;

string html = """
<h1>Invoice #1024</h1>
<p>Total due: <strong>$1,240.00</strong></p>
""";

byte[] pdf = HtmlConverter.ConvertToBytes(html);

File.WriteAllBytes("invoice.pdf", pdf);
Enter fullscreen mode Exit fullscreen mode

No browser process.

No Node.js runtime.

No native interop.

No sidecar service.

Just a managed .NET assembly.

That is the architecture Bhowra.Ink is aiming for.


What matters in production-style documents

I do not think PDF renderers should be evaluated only with demo pages.

The real test is an ugly business document.

The kind of template that has:

  • nested tables
  • logos
  • QR codes
  • custom fonts
  • page breaks
  • mixed languages
  • right-to-left text
  • taxes and totals
  • headers and footers
  • PDF/A requirements
  • repeatable output requirements

That is where PDF renderers either earn trust or lose it.


Operational footprint

The core idea behind Bhowra.Ink is to keep the rendering stack small.

It is positioned as a managed .NET library designed to avoid:

  • Chromium
  • wkhtmltopdf
  • Node.js
  • native binaries
  • external rendering processes
  • third-party runtime dependencies

That matters in environments where installing or launching a browser is painful, restricted, or too heavy for the workload.

A smaller rendering stack also makes audits easier.

There is less to deploy, less to patch, and less to explain.


Performance

The performance target here is not:

Beat a browser at rendering arbitrary web pages.

The target is:

Render common business documents fast enough that PDF generation can stay inside normal request/response flows when appropriate.

For static HTML invoices and reports, avoiding browser startup can make a meaningful difference.

Instead of orchestrating a browser process, the application calls a .NET API and receives PDF bytes.

That changes the architecture.

In some systems, PDF generation can move from:

queue → worker → browser → storage → callback

to:

API → render → return PDF

That simplification is often more valuable than the raw millisecond number.


Determinism

Deterministic output is one of the most important properties for document infrastructure.

If the same HTML, assets, fonts, and options produce stable output, testing becomes much easier.

You can use:

  • checksum comparisons
  • golden-file tests
  • visual regression tests
  • PDF metadata checks
  • CI-based rendering tests

This is especially useful for financial, legal, and compliance documents.

A PDF renderer should not be a black box that changes output because a browser version changed underneath it.


Rendering fidelity

The hard part of HTML-to-PDF is not writing a PDF file.

The hard part is layout.

Real documents need:

  • tables that paginate correctly
  • page breaks that behave
  • headers and footers
  • repeated table headers
  • font embedding
  • text extraction
  • right-to-left shaping
  • predictable spacing
  • borders
  • images
  • QR codes

A renderer aimed at documents does not need to implement the entire modern browser platform.

But the subset it supports must be reliable for document layouts.

That distinction matters.

A browser renderer asks:

Can I render the web?

A document renderer asks:

Can I render this invoice, statement, payslip, report, or contract correctly every time?


Compliance

Business PDFs often have requirements beyond visual appearance.

They may need:

  • PDF/A for archiving
  • PDF/UA for accessibility
  • encryption
  • metadata
  • embedded files
  • QR codes
  • machine-readable invoice data

E-invoicing makes this even more important.

Formats such as Factur-X and ZUGFeRD combine a human-readable PDF with embedded structured XML.

That turns PDF generation into part of the compliance pipeline, not just a print step.

This is one reason I think invoice generation is a better benchmark than a “Hello World” PDF.


E-invoicing and QR codes

Invoices are no longer always just visual documents.

Depending on the market, they may require:

  • tax QR codes
  • embedded XML
  • PDF/A-3 output
  • archival metadata
  • Arabic or Hebrew text
  • custom fonts
  • predictable text extraction

For these workflows, the PDF generator has to do more than make something that looks good on screen.

It has to produce a document that can survive audit, archiving, and machine processing.


Where I would still specify a browser

I would still choose a browser renderer when the input is effectively a web application.

For example:

  • dashboard exports
  • JavaScript charts
  • SPA pages
  • canvas-heavy layouts
  • complex CSS dependent on browser behavior
  • pages that must match Chrome pixel-for-pixel

That is not the workload Bhowra.Ink appears to be trying to own.

The intended workload is static, server-generated HTML for business documents.


Known boundaries

Every renderer has boundaries.

The important thing is to know them before production.

For this kind of browserless renderer, I would expect teams to check:

  • JavaScript is not executed
  • CJK fonts should be supplied explicitly by the application
  • remote fonts should be embedded or made available locally
  • browser APIs are not available
  • SPA rendering is not the target use case
  • image and CSS support should be tested against real production templates

I consider this a strength, not a weakness.

A production dependency should clearly tell you what it does and does not do.


My evaluation standard

I would not choose a PDF engine based on a feature matrix alone.

I would test it like this:

  1. Take the ugliest real template.
  2. Include the real fonts and assets.
  3. Render it on the actual deployment target.
  4. Check page breaks.
  5. Check table layout.
  6. Check text extraction.
  7. Check QR readability.
  8. Check PDF size.
  9. Check render time.
  10. Run it repeatedly and compare output stability.

An hour with a real invoice tells you more than a week reading marketing pages.


The architecture decision

Browser-based rendering solves one problem:

Render web pages as PDFs.

But many enterprise document pipelines have a different problem:

Render static business documents reliably in a server-side .NET environment without carrying a browser runtime.

For workloads like invoices, reports, statements, payslips, contracts, and e-invoicing documents, a small managed renderer can be the more appropriate architecture.

Not because browsers are bad.

Because they solve a larger problem than many document pipelines actually have.


Try it with your own document

The best test is not a sample.

It is your document.

Take one real invoice, report, payslip, or statement.

Render it.

Look at:

  • page breaks
  • fonts
  • borders
  • QR codes
  • RTL text
  • PDF/A requirements
  • text extraction
  • performance
  • deployment behavior

That will tell you quickly whether a browserless renderer fits your workload.

Project: https://bhowra.com/bhowra-ink.html

NuGet: https://www.nuget.org/packages/Bhowra.Ink/


Disclosure: I am helping with early feedback for Bhowra.Ink.

Top comments (0)