Comparison
A PHP and Laravel alternative to dompdf
dompdf is the most-installed PHP PDF library. It runs inside your PHP process, parses HTML, and renders to PDF using its own layout engine. It works for simple documents, but its CSS support is frozen at a subset of CSS 2.1 with no flexbox or grid, so modern frameworks like Tailwind and Bootstrap do not render faithfully. JavaScript is not supported, and complex layouts often require workarounds or produce incorrect output. PDFPipe renders with a real browser engine from a single HTTP call, so any HTML and CSS that works in a browser works in the PDF.
dompdf versus a dedicated PDF API
| PDFPipe | dompdf | |
|---|---|---|
| CSS support | Complete (browser-level) | CSS 2.1 subset only |
| Flexbox / Grid | Yes | No |
| JavaScript | Runs before capture | Not supported |
| Web fonts | Any URL, loaded automatically | Must embed manually |
| Memory usage | None in your process | Spikes on complex docs |
| Install | No Composer package | composer require dompdf/dompdf |
| PHP version lock | None | Tied to your PHP version |
| Runs in | Any language, one HTTP call | PHP only |
The CSS 2.1 ceiling
dompdf's HTML parser and layout engine implement a subset of CSS 2.1. Flexbox, CSS Grid, custom properties, clamp(), and most modern CSS are not supported. This means any template that looks correct in a browser will need to be rewritten or simplified before dompdf can render it acceptably. As your UI evolves, the dompdf template needs to be kept in sync separately. PDFPipe has no CSS ceiling: if it renders in Chrome, it renders in the PDF.
Memory and process isolation
dompdf loads your entire HTML document into PHP memory, runs its layout engine, and generates the PDF all inside your web process. Complex invoices or long reports can exhaust PHP's memory limit and crash the request. On shared hosting this is unrecoverable. PDFPipe does all rendering in an isolated process on our infrastructure. Your PHP process makes one HTTP call and receives the finished PDF.
Plain PHP
<?php
// Works in plain PHP, Laravel, Symfony, or any framework.
$html = <<<HTML
<html>
<body style="font-family: system-ui; padding: 40px">
<h1 style="color:#d23a1d">Invoice #4012</h1>
<p>Acme Corp · 12 June 2026</p>
</body>
</html>
HTML;
$response = file_get_contents('https://api.pdfpipe.xyz/v1/pdf', false,
stream_context_create([
'http' => [
'method' => 'POST',
'header' => [
'Authorization: Bearer ' . getenv('PDFPIPE_API_KEY'),
'Content-Type: application/json',
],
'content' => json_encode([
'html' => $html,
'options' => ['format' => 'A4'],
]),
],
])
);
file_put_contents('invoice.pdf', $response);Laravel
Render your Blade template to an HTML string, POST it to PDFPipe, and stream the response back to the browser:
// In a Laravel controller — uses the built-in Http facade.
use Illuminate\Support\Facades\Http;
public function invoice(string $id): \Symfony\Component\HttpFoundation\StreamedResponse
{
$html = view('invoices.show', ['invoice' => Invoice::findOrFail($id)])->render();
$res = Http::withToken(config('services.pdfpipe.key'))
->post('https://api.pdfpipe.xyz/v1/pdf', [
'html' => $html,
'options' => ['format' => 'A4'],
]);
abort_unless($res->successful(), 502, 'PDF render failed.');
return response()->streamDownload(
fn () => print($res->body()),
"invoice-{$id}.pdf",
['Content-Type' => 'application/pdf'],
);
}When to keep dompdf
dompdf is reasonable when you have no outbound HTTP from your server, the document is simple enough to stay within CSS 2.1, and you need a fully offline solution. For anything involving modern CSS, web fonts, or production-quality output, a browser-based render API produces better results with significantly less code.
Full PHP and Laravel examples on the Laravel guide and PHP guide.
See pricing →