Oh Dear is the all-in-one monitoring tool for your entire website. We monitor uptime, SSL certificates, broken links, scheduled tasks and more. You'll get a notifications for us when something's wrong. All that paired with a developer friendly API and kick-ass documentation. O, and you'll also be able to create a public status page under a minute. Start monitoring using our free trial now.

Laravel PDF v2 has been released: adds support for Laravel Cloud and easy queuing

Original – by Freek Van der Herten – 6 minute read

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.

Stay up to date with all things Laravel, PHP, and JavaScript.

You can follow me on these platforms:

On all these platforms, regularly share programming tips, and what I myself have learned in ongoing projects.

Every month I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.