How to Convert HTML to PDF in Python, Go, PHP, and Node.js (Free & Easy Methods Compared)
Learn how to convert HTML to PDF for free in Python, Go, PHP, and Node.js. Compare popular tools like wkhtmltopdf, Puppeteer, Dompdf, and WeasyPrint, and see when it makes sense to switch to an API-based solution like BlazePDF.
Why Convert HTML to PDF?
PDFs are the go-to format for invoices, reports, tables, tickets, or contracts. Most apps eventually need a way to take an HTML template (with your layout, data, and branding) and generate a professional PDF.
There are plenty of open-source ways to do this. Let's look at the most common free HTML-to-PDF options in Python, Go, PHP, and Node.js, and compare how they perform in real-world use cases.
π Convert HTML to PDF in Python
Python offers a few strong libraries for this:
1. pdfkit (wkhtmltopdf wrapper)
import pdfkit
pdfkit.from_file("example.html", "output.pdf")
-
β Works with HTML, URLs, or strings
-
β Requires
wkhtmltopdfinstalled -
β οΈ Can misrender tables with complex row/column spans
2. WeasyPrint
from weasyprint import HTML
HTML("example.html").write_pdf("output.pdf")
-
β Pure Python, no extra binary
-
β Slower on complex layouts
-
β οΈ Still struggles with table formatting in some edge cases
3. Pyppeteer (Headless Chrome)
import asyncio
from pyppeteer import launch
async def main():
browser = await launch()
page = await browser.newPage()
await page.goto("<https://example.com>")
await page.pdf({"path": "output.pdf"})
await browser.close()
asyncio.run(main())
-
β Full CSS and JS rendering (just like Chrome)
-
β Heavy dependency (Chromium)
-
β οΈ Known memory leaks in headless Chromium can cause servers to crash under load
β‘ Convert HTML to PDF in Go
1. go-wkhtmltopdf
pdfg, _ := wkhtmltopdf.NewPDFGenerator()
pdfg.AddPage(wkhtmltopdf.NewPageReader(strings.NewReader("<h1>Hello Go</h1>")))
pdfg.Create()
pdfg.WriteFile("output.pdf")
-
β Simple, lightweight
-
β Depends on wkhtmltopdf binary
-
β οΈ Same table rendering issues as Python's wkhtmltopdf wrappers
2. chromedp (Headless Chrome)
chromedp.Run(ctx,
chromedp.Navigate("https://example.com"),
chromedp.ActionFunc(func(ctx context.Context) error {
buf, _, err := page.PrintToPDF().Do(ctx)
return err
}),
)
-
β Accurate, browser-level rendering
-
β Requires Chrome, higher memory usage
-
β οΈ Exposed to Chromium's headless memory leaks in production
π Convert HTML to PDF in PHP
1. Dompdf
$dompdf = new Dompdf();
$dompdf->loadHtml("<h1>Hello World</h1>");
$dompdf->render();
$dompdf->stream("output.pdf");
-
β Composer package, easy to install
-
β Limited support for advanced CSS
-
β οΈ Table rendering is inconsistent with borders, merged cells, and alignment
2. wkhtmltopdf via exec
exec("wkhtmltopdf example.html output.pdf");
-
β Reliable, stable output
-
β Requires wkhtmltopdf installed on the server
-
β οΈ Same table rendering issues
βοΈ Convert HTML to PDF in Node.js
1. Puppeteer (Headless Chrome)
const puppeteer = require("puppeteer");
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto("<https://example.com>", { waitUntil: "networkidle0" });
await page.pdf({ path: "output.pdf", format: "A4" });
await browser.close();
})();
-
β Handles modern HTML, CSS, and JS
-
β Heavy, large install size
-
β οΈ Long-running servers hit Chromium headless memory leak issues
2. html-pdf (wkhtmltopdf wrapper)
const pdf = require("html-pdf");
pdf.create("<h1>Hello World</h1>").toFile("./output.pdf", (err, res) => {
if (err) return console.log(err);
console.log(res);
});
-
β Lightweight alternative
-
β Still requires wkhtmltopdf
-
β οΈ Suffers from the same table rendering limitations
π Comparison of Methods
| Language | Option | Pros | Cons |
|---|---|---|---|
| Python | pdfkit, WeasyPrint, Pyppeteer | Flexible, multiple choices | Table rendering bugs, dependencies, memory leaks |
| Go | go-wkhtmltopdf, chromedp | Reliable output | Table rendering issues, Chromium memory overhead |
| PHP | Dompdf, wkhtmltopdf | Easy setup | Poor CSS/JS support, unreliable table layouts |
| Node.js | Puppeteer, html-pdf | Accurate rendering | Heavy installs, Chromium memory leaks |
π§ The Real-World Drawbacks
Here's what you'll notice once you move beyond toy examples:
-
Tables are hard. Almost every free library struggles with HTML tables that have merged rows/columns, nested elements, or advanced styling. If your documents rely heavily on tabular data (think invoices or financial reports), this becomes a real headache.
-
Chromium memory leaks are real. Even with modern headless browsers, long-running processes in production environments accumulate memory. While your OS can handle this in desktop Chrome, in headless servers it often causes slowdowns or crashes over time.
-
Scaling isn't free. Each PDF generation can consume hundreds of MBs of RAM for even simple documents, which doesn't play nicely when you scale out.
π Why Use a PDF Conversion API Instead?
For side projects or small apps, the free tools are fine. But if you're building something serious and customer-facing, the drawbacks start adding up:
-
Maintaining wkhtmltopdf or Chrome binaries across environments
-
Debugging table rendering quirks that throw off invoice layouts
-
Restarting workers or containers due to Chromium memory leaks
-
Losing time you'd rather spend on your actual application logic
This is where an API-based approach comes in. With BlazePDF, you send your HTML and get back a pixel-perfect PDF - without worrying about infrastructure, memory leaks, or rendering inconsistencies.
-
Reliable uptime and scaling handled for you
-
Consistent table rendering and layout accuracy
-
No heavy binaries or OS-level dependencies
-
Lets you focus on shipping features, not babysitting PDFs
π If you're at the stage where PDFs matter to your business but maintaining infrastructure doesn't, BlazePDF is worth a look.