Laravel PDF v2 has been released: adds support for Laravel Cloud and easy queuing
A while ago, we released laravel-pdf, a package to generate PDFs in Laravel apps.
Under the hood, it used Browsershot (and therefore Puppeteer/Chrome) to convert HTML to PDF. That approach works great, but it does require Node.js and a headless Chrome binary on your server.
Last week, my buddy Dries shared on X how to generate PDFs using Cloudflare services. This way doesn’t require Node or any binaries. Very neat! This unlocks PDF generation for environments where Node or Chrome cannot be installed easily, like Laravel Cloud.
To support this way of rendering a PDF, we’ve released a new major release (v2) of Laravel PDF. The package now ships with three drivers: Browsershot, Cloudflare Browser Rendering, and DOMPDF. You can also create your own driver. On top of that, we've added queued PDF generation and the ability to set PDF metadata. And to let your AI understand our package, we've added a Laravel Boost skill.
Let me walk you through all of it.
Basic usage
The API for generating a PDF hasn't changed. You can use the Pdf facade or the pdf() helper to create a PDF from a Blade view:
use Spatie\LaravelPdf\Facades\Pdf; Pdf::view('invoice', ['invoice' => $invoice]) ->save('/some/path/invoice.pdf');
Returning a PDF response from a controller is simple. Because under the hood our PDF builder implements Laravel’s Responsible interface, you can just return it in your controller.
use function Spatie\LaravelPdf\Support\pdf; class DownloadInvoiceController { public function __invoke(Invoice $invoice) { return pdf() ->view('pdf.invoice', compact('invoice')) ->name('invoice-2023-04-10.pdf'); } }
The driver architecture
In v1, the package was tightly coupled to Browsershot. In v2, we moved to a driver based architecture. Out of the box, we ship three drivers:
- Browsershot: uses a headless Chrome browser via spatie/browsershot. Highest fidelity rendering, but requires Node.js and Chrome on your server.
- Cloudflare: uses Cloudflare's Browser Rendering API. Same Chrome-based quality, but runs on Cloudflare's infrastructure. No binaries needed on your server.
- DOMPDF: uses dompdf/dompdf. Pure PHP, no external dependencies at all. Great for simple documents, though complex CSS may not render perfectly.
You set the default driver in the config file:
// config/laravel-pdf.php return [ 'driver' => env('LARAVEL_PDF_DRIVER', 'browsershot'), // ... ];
The Cloudflare driver uses Cloudflare's Browser Rendering API, which means you get Chrome-quality PDFs without installing any binaries on your server.
To use this way of rendering, you need to set driver to cloudflare and provide a Cloudflare API token and account id. Our docs mention how to get these Cloudflare values.
LARAVEL_PDF_DRIVER=cloudflare CLOUDFLARE_API_TOKEN=your-api-token CLOUDFLARE_ACCOUNT_ID=your-account-id
That's it. All your existing Pdf::view() calls will now use Cloudflare instead of Browsershot. No code changes needed.
DOMPDF is the most portable option. It's pure PHP -- no Node.js, no Chrome, no external services.
To use it with our packagage, just install the package...
composer require dompdf/dompdf
... and then set the driver:
LARAVEL_PDF_DRIVER=dompdf
The DOMPDF driver handles things like paper size, margins, and orientation automatically. Be aware that DOMPDF doesn't support the same level of CSS as a real browser. For invoices and simple documents, it works well. For complex layouts with modern CSS, you'll want Browsershot or Cloudflare.
If your HTML references remote images or stylesheets, enable remote loading in the config:
// config/laravel-pdf.php 'dompdf' => [ 'is_remote_enabled' => true, ],
Queued PDF generation
Generating a PDF can take a moment, especially with the Browsershot or Cloudflare drivers. In v2, you can push the generation to a queue:
Pdf::view('invoice', ['invoice' => $invoice]) ->saveQueued('/path/to/invoice.pdf');
This dispatches a job that generates the PDF in the background.
You can register callbacks for when the job succeeds or fails, using an API inspired by how Laravel AI handles its async operations:
Pdf::view('invoice', ['invoice' => $invoice]) ->saveQueued('/path/to/invoice.pdf') ->then(function (string $path, ?string $diskName) { // PDF was generated successfully Mail::to($user)->send(new InvoiceGenerated($path)); }) ->catch(function (Throwable $exception) { // Something went wrong Log::error('PDF generation failed', ['error' => $exception->getMessage()]); });
The then callback receives the file path and an optional disk name. The catch callback receives the exception.
You can also save queued PDFs to a specific disk:
Pdf::view('invoice', ['invoice' => $invoice]) ->disk('s3') ->saveQueued('invoices/invoice-123.pdf');
And you can specify the queue connection and queue name:
Pdf::view('invoice', ['invoice' => $invoice]) ->saveQueued('/path/to/invoice.pdf', connection: 'redis', queue: 'pdfs');
If you need to customize the job class (for example, to set $tries or $timeout), you can extend GeneratePdfJob and register it in the config:
// config/laravel-pdf.php 'job' => App\Jobs\MyCustomPdfJob::class,
Laravel Boost skill
Laravel recently introduced Boost, a way for packages to ship "skills" that teach AI coding agents how to use them correctly. Instead of an AI guessing at your package's API (and getting it wrong), a Boost skill provides it with the right context about available methods, drivers, and configuration options.
Laravel PDF v2 ships with a Boost skill out of the box. After installing the package, run php artisan boost:install to register it. From that point on, any AI agent working in your project will know how to generate correct PDF code — which driver options are available, how to queue PDF generation, how to set metadata, and so on.
PDF metadata
v2 adds a meta() method to set PDF metadata like title, author, and creation date:
Pdf::view('invoice', ['invoice' => $invoice]) ->meta( title: 'Invoice #123', author: 'Spatie', subject: 'Monthly invoice', keywords: 'invoice, billing', creator: 'My Application', creationDate: now(), ) ->save('/path/to/invoice.pdf');
All parameters are optional, you can just pass the ones you need.
Testing
The package has first-class testing support. Call Pdf::fake() to swap the real PDF builder for a fake one that captures everything without actually generating PDFs:
use Spatie\LaravelPdf\Facades\Pdf; it('generates an invoice pdf', function () { Pdf::fake(); // Run your code that generates a PDF... Pdf::assertSaved('/path/to/invoice.pdf'); });
You can assert on the view, view data, content, and more:
Pdf::assertViewIs('invoice'); Pdf::assertViewHas('invoice', $invoice); Pdf::assertSee('Invoice #123'); Pdf::assertDontSee('Draft');
And for queued PDFs, there's assertQueued and assertNotQueued:
Pdf::assertQueued('/path/to/invoice.pdf'); Pdf::assertNotQueued();
In closing
You can find the code of the package on GitHub. We also have extensive docs on our website.
This is one of the many packages we've created at Spatie. If you want to support our open source work, consider picking up one of our paid products.