Engineering Feb 18, 2026 • 12 min read

The Hard Truth About Running Puppeteer in Production

"It worked on my machine." The famous last words of every developer who just deployed a Puppeteer-based PDF generator to a 1GB RAM VM.

Rendering HTML to PDF is a deceptively simple task. You install Puppeteer, you call page.pdf(), and you get a buffer. On your local machine with 16GB of RAM and a single user (you), it feels like magic.

Then you deploy.

1. The Memory Pressure Paradox

A single headless Chromium instance takes anywhere from 150MB to 500MB of RAM just to stay alive. When you start rendering complex documents—think Tailwind-heavy dashboards or 50-page reports—that number spikes.

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

In a constrained environment like a Fly.io VM or an AWS Lambda function, you don't have the luxury of "infinite ram." You have to manage the lifecycle.

2. The Zombie Process Apocalypse

Chromium doesn't always want to die. If your Node.js process crashes or if a timeout triggers incorrectly, the 'headless' processes stays in memory. They become zombies—orphaned processes that continue to eat CPU cycles and lock down the filesystem.

In production, you need a Sentinel. A process that monitors the PID tree and forcefully sends a SIGKILL to any process that has outlived its usefulness. Most self-hosted solutions forget this, leading to "Server Rebooting" as the only fix.

3. Scaling Concurrency vs. Throughput

You can't just run 10 browsers at once on a small VM. You need a Concurrency Manager. You need to queue requests and process them based on available resource slabs.

At RocketUtils, we use a custom concurrency manager that tracks the 'cost' of a request. A 10KB HTML snippet has a different cost than a 2MB URL. We tier our workers so that light requests don't get stuck behind heavy ones.

4. Security: The SSRF Elephant in the Room

This is the one that keeps CTOs awake. If a user can pass a URL to your PDF generator, they can pass http://169.254.169.254/latest/meta-data/. If your server is on AWS, they now have your IAM role credentials.

Securing Puppeteer requires network-level sandboxing. You must block all private IP ranges at the firewall or proxy level before the browser even attempts the navigation.

Why we built RocketUtils

We spent months fighting these exact battles. We built the reaping engines, the SSRF proxies, and the V8 memory sentinels so you don't have to.

RocketUtils is a Managed Rendering Infrastructure. You send the HTML, we handle the hard truth of production Puppeteer.

Stop Fighting the Lifecycle

Get 100 free PDFs per month and offload your infra debt today.

Claim Your API Key