spatie/laravel-pdf
Generate PDFs from Laravel Blade views with a simple fluent API. Choose drivers like Browsershot/Chromium, Gotenberg, Cloudflare Browser Run, WeasyPrint, DOMPDF, or chrome-php. Use modern CSS, set page formats, and stream or save PDFs.
Installation:
composer require spatie/laravel-pdf
php artisan vendor:publish --provider="Spatie\Pdf\PdfServiceProvider" --tag="pdf-config"
Configure your preferred driver in config/pdf.php (e.g., browsershot, dompdf, or gotenberg).
First Use Case: Generate a PDF from a Blade view in a controller:
use Spatie\LaravelPdf\Facades\Pdf;
public function generatePdf()
{
return Pdf::view('pdfs.invoice', ['data' => $data])
->name('invoice.pdf');
}
Key Files:
config/pdf.php: Driver and default settings.resources/views/pdfs/: Store Blade templates for PDFs.app/Providers/AppServiceProvider.php: Register custom drivers if needed.Dynamic PDF Generation: Use Blade views with dynamic data:
Pdf::view('pdfs.report', ['users' => User::all()])
->format('a4')
->save(storage_path('app/reports/report.pdf'));
Conditional Formatting: Apply rules based on data:
Pdf::view('pdfs.order', ['order' => $order])
->when($order->isUrgent(), fn ($pdf) => $pdf->margins(10))
->unless($order->isDigital(), fn ($pdf) => $pdf->headerView('pdfs.header'));
Reusable PDF Builders: Create a service class for complex PDFs:
class InvoicePdfService {
public function generate(Invoice $invoice) {
return Pdf::view('pdfs.invoice', ['invoice' => $invoice])
->meta(title: "Invoice #{$invoice->id}")
->format('a4')
->name("invoice_{$invoice->id}.pdf");
}
}
Testing PDFs:
Use the Pdf::fake() facade for unit tests:
it('generates a PDF with correct content', function () {
Pdf::fake();
$response = $this->get('/pdf/invoice');
Pdf::assertRespondedWithPdf(fn ($pdf) => $pdf->contains('Total'));
});
Queue PDF Generation: Use Laravel queues to offload PDF generation:
Pdf::view('pdfs.heavy-report', ['data' => $data])
->save(storage_path('app/reports/heavy-report.pdf'))
->dispatch(); // Dispatch to queue
Custom Drivers:
Extend the PdfDriver class for bespoke logic:
class CustomDriver extends PdfDriver {
public function generate($view, $data) {
// Custom logic
return parent::generate($view, $data);
}
}
PDF Metadata: Set metadata dynamically:
Pdf::view('pdfs.document', ['doc' => $doc])
->meta([
'title' => "Document #{$doc->id}",
'author' => $doc->user->name,
'keywords' => 'document, ' . $doc->category,
]);
Headers/Footers: Use shared Blade views for consistency:
<!-- resources/views/pdfs/partials/footer.blade.php -->
<footer>
Page @pageNumber of @totalPages | {{ config('app.name') }}
</footer>
Pdf::view('pdfs.document', ['doc' => $doc])
->footerView('pdfs.partials.footer');
Driver Compatibility:
Image Paths:
Absolute paths (e.g., https://example.com/logo.png) work in headers/footers, but relative paths (e.g., public_path('logo.png')) may fail. Use @inlinedImage:
@inlinedImage(public_path('logo.png'))
Margins and Scaling:
mm by default. Use Unit::Pixel for pixel precision.->scale(0.75)) only works with Chromium-based drivers.Page Ranges: Only supported by Browsershot/Cloudflare. DOMPDF ignores this.
Tagged PDFs:
Only Browsershot/Cloudflare support accessibility features like ->tagged().
Memory Limits:
Complex PDFs (e.g., large tables) may hit memory limits. Use ->scale() or simplify CSS.
Inspect Builder State:
Pdf::view('pdfs.document', ['doc' => $doc])
->dump(); // Dump current settings
Check Driver Logs: For Browsershot/Gotenberg, check Chromium logs or Docker logs for errors.
Validate HTML/CSS: Test Blade views in a browser first to ensure rendering works before PDF generation.
Fallback Drivers:
Configure a fallback driver in config/pdf.php:
'fallback' => 'dompdf',
Caching: Cache generated PDFs to avoid reprocessing:
$path = storage_path("app/cache/invoice_{$invoice->id}.pdf");
if (!file_exists($path)) {
Pdf::view('pdfs.invoice', ['invoice' => $invoice])
->save($path);
}
return response()->file($path);
Dynamic Filenames:
Use Str::slug() for safe filenames:
->name("invoice_{$invoice->id}_{$invoice->created_at->format('Y-m-d')}.pdf")
Local Testing:
Use dompdf for local development (no external dependencies):
'driver' => env('PDF_DRIVER', 'dompdf'),
Production Optimization:
For Gotenberg/Browsershot, set ->timeout(30) to avoid hanging.
Laravel Boost:
Run php artisan boost:install to enable AI-assisted PDF generation in IDEs.
Custom CSS: Reset default styles in PDF Blade views:
<style>
body { margin: 0; font-family: Arial; }
</style>
Environment-Specific Drivers:
Use .env to switch drivers:
PDF_DRIVER=dompdf
config(['pdf.driver' => env('PDF_DRIVER', 'browsershot')]);
PDF-to-Text Testing:
Install poppler-utils (brew install poppler-utils) to verify text extraction:
pdftotext path/to/generated.pdf
How can I help you explore Laravel packages today?