Copied!
Laravel

Mastering High-Performance PDF and Code Generation in Laravel

laravel-high-performance-pdf-code-generation
Shahroz Javed
Dec 21, 2025 . 183 views

Generating PDFs in Laravel is deceptively expensive. What works perfectly in development can easily collapse under real traffic due to blocking requests, memory spikes, and CPU saturation. This guide focuses on building a high-performance, production-safe PDF generation pipeline using queues, strict memory limits, and streaming strategies.

Why High-Performance PDF Generation Matters

PDF generation is not a simple rendering task. It involves HTML parsing, layout calculation, font embedding, and binary output. When handled synchronously, it can:

  • Block HTTP requests

  • Cause PHP memory exhaustion

  • Slow down unrelated requests

  • Crash workers under concurrency

⚠️ Never generate large PDFs synchronously in a controller on a production system.

Queue-Based PDF Generation Architecture

The foundation of high-performance PDF generation is asynchronous processing. Laravel queues allow us to move CPU- and memory-heavy work outside the request lifecycle.

Installing Redis Queue Dependencies

composer require predis/predis

Configure Redis and queue settings in your environment file:

REDIS_CLIENT=predis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

QUEUE_CONNECTION=redis

Running Queue Workers with Memory Limits

php artisan queue:work redis --memory=256 --timeout=120

This ensures workers are restarted before memory leaks accumulate.

Dispatching PDF Jobs Instead of Blocking Requests

The controller’s responsibility should be minimal: dispatch the job and return immediately.

Route::get('/shipments/pdf', function () {

    $order = 'IB-2025-000001';

    GenerateShipmentPdf::dispatch(
        orderNo: $order,
        url: 'https://yourdomain.com/order/IB-2025-000001'
    );

    return response()->json([
        'status' => 'queued',
        'message' => 'PDF generation started'
    ]);
});

This approach guarantees low response times regardless of PDF complexity.

High-Performance PDF Job Implementation

The job class is where performance discipline matters most.

<?php

namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
use Barryvdh\DomPDF\Facade\Pdf;

class GenerateShipmentPdf implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $timeout = 120;
    public int $tries = 3;

    public function __construct(
        protected string $orderNo,
        protected string $url
    ) {}

    public function handle(): void
    {
        $pdf = Pdf::loadView('barcode.pdf', [
            'order_no' => $this->orderNo,
            'url' => $this->url,
        ]);

        $pdf->setPaper('a4');
        $pdf->setOptions([
            'isHtml5ParserEnabled' => true,
            'isRemoteEnabled' => false,
            'isPhpEnabled' => false,
            'debugCss' => false,
            'debugLayout' => false,
            'dpi' => 96,
        ]);

        Storage::put(
            "pdfs/shipments/{$this->orderNo}.pdf",
            $pdf->output()
        );
    }
}

Memory Limits and Worker Stability

Unbounded memory usage is the most common reason PDF systems fail under load. Always limit memory at the worker level.

memory_limit = 256M
⚠️ Never set memory_limit to unlimited. Restarting workers is cheaper than crashing servers.

Reducing DomPDF Memory Footprint

DomPDF ships with features that are unnecessary in most backend PDF workflows. Disable everything you do not need.

$pdf->setOptions([
    'isRemoteEnabled' => false,
    'isPhpEnabled' => false,
    'debugCss' => false,
    'debugLayout' => false,
]);

Blade Rules for PDF Templates

  • No background images

  • No web fonts

  • Inline styles only

  • Avoid large SVG files

PDF templates should be treated as rendering documents, not web pages.

Chunking Large Data Sets

Large reports and invoices must never load all records into memory.

OrderItem::where('order_id', $id)
    ->chunk(200, function ($items) {
        // Render partial rows
    });

Streaming vs Buffering PDF Output

How you deliver the PDF matters as much as how you generate it.

Buffering Output (Default, Not Ideal)

$pdf->output();

Buffering holds the entire PDF in memory before sending it to the client. This does not scale for large documents or high traffic.

Streaming Output (Preferred)

return response()->streamDownload(function () use ($pdf) {
    echo $pdf->output();
}, 'shipment.pdf');

Streaming reduces peak memory usage and improves response stability under load.

Load Testing PDF Generation

Never assume performance. Measure it.

During load testing, monitor:

  • HTTP response time

  • Queue wait time

  • Worker memory usage

  • Failed and retried jobs

💡 High-performance systems are proven under load, not assumed during development.

Conclusion

High-performance PDF generation in Laravel is not about faster libraries. It is about architecture, isolation, and discipline. By using queues, enforcing memory limits, streaming output, and validating under load, you can safely scale PDF generation without sacrificing system stability.

🚀 Related: Scaling Laravel queue workers horizontally with Supervisor and Redis.
📑 On This Page