📄 Laravel PDF Generator Comparison

This article compares popular PDF generation solutions in Laravel.

📋 Table of Contents

Introduction

This article demonstrates how to implement two popular solutions for PDF generation in Laravel: Spatie Laravel PDF (with Browsershot) and barryvdh/laravel-dompdf. Both have their strengths and limitations—below you'll find setup instructions, usage examples, a comparison, and recommendations for when to use each.

Installation & Setup

1. Spatie Laravel PDF (Browsershot)

  • Install the package:
    composer require spatie/laravel-pdf
    npm install puppeteer
    npx puppeteer browsers install chrome
    
  • Make sure Chromium is installed in your Docker PHP image (if using Docker):
    RUN apt-get update \
        && apt-get install -y wget gnupg2 \
        && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
        && echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
        && apt-get update \
        && apt-get install -y google-chrome-stable \
        && apt-get clean \
        && rm -rf /var/lib/apt/lists/*
    

2. barryvdh/laravel-dompdf

  • Install the package:
    composer require barryvdh/laravel-dompdf
    php artisan vendor:publish --provider="Barryvdh\DomPDF\ServiceProvider"
    
  • No extra system dependencies required. Styling is limited to basic CSS.

Example Routes and Controller

In routes/web.php:

Route::get('/pdf/spatie', [PdfDemoController::class, 'spatie'])->name('pdf.spatie');
Route::get('/pdf/dompdf', [PdfDemoController::class, 'dompdf'])->name('pdf.dompdf');

In app/Http/Controllers/PdfDemoController.php:

<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use Barryvdh\DomPDF\Facade\Pdf as DomPdf;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Spatie\Browsershot\Browsershot;
use Spatie\LaravelPdf\Facades\Pdf;

class PdfDemoController extends Controller
{
    public function spatie(Request $request)
    {
        $data = [
            'user' => [
                'name' => 'John Doe',
                'email' => '[email protected]',
            ],
            'items' => [
                ['name' => 'Super Product', 'qty' => 2, 'price' => 199.99],
                ['name' => 'Mega Service', 'qty' => 1, 'price' => 499.00],
            ],
            'total' => 199.99 * 2 + 499.00,
        ];

        return Pdf::view('pdfs.spatie-invoice', $data)
            ->withBrowsershot(function (Browsershot $browsershot): void {
                $browsershot->noSandbox()->format('A4');
            })
            ->download('spatie-invoice.pdf');
    }

    public function dompdf(Request $request): Response
    {
        $data = [
            'invoice_number' => 'FV/2024/05/001',
            'date' => now()->toDateString(),
            'client' => 'Jane Doe',
            'items' => [
                ['name' => 'Product A', 'qty' => 3, 'price' => 100],
                ['name' => 'Product B', 'qty' => 1, 'price' => 250],
            ],
            'total' => 3 * 100 + 250,
        ];

        return DomPdf::loadView('pdfs.dompdf-invoice', $data)->download('dompdf-invoice.pdf');
    }
}

Example Views

Spatie Laravel PDF (Tailwind, modern layout)

resources/views/pdfs/layouts/pdf.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>@yield('title', 'PDF')</title>
    <style>
        body { font-family: 'Inter', sans-serif; }
    </style>
    @yield('styles')
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 p-8">
@yield('content')
</body>
</html>

resources/views/pdfs/spatie-invoice.blade.php:

@extends('pdfs.layouts.pdf')

@section('title', 'Invoice (Spatie Laravel PDF)')

@section('content')
<div class="max-w-2xl mx-auto bg-white rounded shadow p-8">
    <div class="flex justify-between items-center mb-8">
        <div>
            <h1 class="text-2xl font-bold text-gray-800">INVOICE</h1>
            <p class="text-gray-500">Seller: <span class="font-semibold">{{ $user['name'] }}</span></p>
            <p class="text-gray-500">Email: {{ $user['email'] }}</p>
        </div>
        <div class="text-right">
            <p class="text-gray-500">Date: {{ now()->toDateString() }}</p>
            <p class="text-gray-500">Invoice No: INV/{{ now()->format('Y') }}/{{ now()->format('m') }}/001</p>
        </div>
    </div>
    <table class="w-full mb-8 text-sm border">
        <thead>
        <tr class="bg-gray-200">
            <th class="p-2 border">#</th>
            <th class="p-2 border text-left">Item</th>
            <th class="p-2 border">Quantity</th>
            <th class="p-2 border">Unit Price</th>
            <th class="p-2 border">Total</th>
        </tr>
        </thead>
        <tbody>
        @foreach($items as $i => $item)
        <tr class="border-b">
            <td class="p-2 border text-center">{{ $i+1 }}</td>
            <td class="p-2 border">{{ $item['name'] }}</td>
            <td class="p-2 border text-center">{{ $item['qty'] }}</td>
            <td class="p-2 border text-right">${{ number_format($item['price'], 2) }}</td>
            <td class="p-2 border text-right">${{ number_format($item['qty'] * $item['price'], 2) }}</td>
        </tr>
        @endforeach
        </tbody>
        <tfoot>
        <tr>
            <td colspan="4" class="p-2 border text-right font-bold">Total</td>
            <td class="p-2 border text-right font-bold">${{ number_format($total, 2) }}</td>
        </tr>
        </tfoot>
    </table>
    <div class="text-xs text-gray-400 mt-8">Generated automatically by Spatie Laravel PDF + TailwindCSS</div>
</div>
@endsection

DomPDF (simple layout)

resources/views/pdfs/dompdf-invoice.blade.php:

@extends('pdfs.layouts.pdf')

@section('title', 'Invoice (Spatie Laravel PDF)')
@section('styles')
<style>
    body { font-family: DejaVu Sans, sans-serif; }
    table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
    th, td { border: 1px solid #ccc; padding: 6px 10px; }
    th { background: #eee; }
    .text-right { text-align: right; }
    .text-center { text-align: center; }
</style>
@endsection
@section('content')
<body>
<h2>INVOICE (DomPDF)</h2>
<p>Invoice No: <strong>{{ $invoice_number }}</strong></p>
<p>Date: <strong>{{ $date }}</strong></p>
<p>Client: <strong>{{ $client }}</strong></p>
<table>
    <thead>
    <tr>
        <th>#</th>
        <th>Item</th>
        <th>Quantity</th>
        <th>Unit Price</th>
        <th>Total</th>
    </tr>
    </thead>
    <tbody>
    @foreach($items as $i => $item)
    <tr>
        <td class="text-center">{{ $i+1 }}</td>
        <td>{{ $item['name'] }}</td>
        <td class="text-center">{{ $item['qty'] }}</td>
        <td class="text-right">${{ number_format($item['price'], 2) }}</td>
        <td class="text-right">${{ number_format($item['qty'] * $item['price'], 2) }}</td>
    </tr>
    @endforeach
    </tbody>
    <tfoot>
    <tr>
        <td colspan="4" class="text-right"><strong>Total</strong></td>
        <td class="text-right"><strong>${{ number_format($total, 2) }}</strong></td>
    </tr>
    </tfoot>
</table>
<p style="font-size: 10px; color: #888;">Generated automatically by barryvdh/laravel-dompdf</p>
</body>
@endsection

Comparison & Recommendations

FeatureSpatie Laravel PDF (Browsershot)barryvdh/laravel-dompdf
EngineHeadless Chrome (Puppeteer)DomPDF (PHP)
Requires Chrome/ChromiumYesNo
StylingFull CSS, Tailwind, grid, flexboxBasic CSS only
Modern layoutsYesLimited
Rendering qualityExcellentGood/Average
SpeedSlower (Chrome startup)Fast (pure PHP)
JS supportYes (limited)No
SVG supportYesLimited
Setup complexityMedium (Docker, Node, Chrome)Very easy
Docker/CI compatibilityYes (with noSandbox)Yes

When to use?

  • Spatie Laravel PDF (Browsershot): When you need beautiful, modern PDFs, want to use Tailwind, grid, flexbox, SVG, and your environment supports Chrome/Chromium (e.g., Docker, dedicated server). Use withBrowsershot() to customize options for Docker/CI.
  • barryvdh/laravel-dompdf: When you need simple PDFs, want a quick setup, and don't need advanced CSS or JS features (e.g., simple invoices, confirmations).

Summary

Both solutions have their place in the Laravel ecosystem. For modern projects where design and layout flexibility matter, choose Spatie Laravel PDF (with Browsershot). For simple use-cases where speed and simplicity are key, barryvdh/laravel-dompdf is sufficient.

Source Code


Follow me on LinkedIn for more Laravel & DevOps tips and updates!

Would you like to learn more about PDF Generation in Laravel? Leave a comment below!

Comments (0)
Leave a comment

© 2025 All rights reserved.