Skip to content

NextPDF Laravel quickstart

In this tutorial, you build a downloadable Portable Document Format (PDF) file from a controller. Then you move the same work to a queued job. Each snippet matches behavior that the package test suite asserts.

Terminal window
composer require nextpdf/laravel
php artisan vendor:publish --tag=nextpdf-config

Three entry points cover almost every Laravel use case. The facade gets you started fastest. PdfResponse turns a document into a Hypertext Transfer Protocol (HTTP) response. A queued job moves heavy generation off the request thread, so you do not wait for it. This tutorial walks through each entry point in turn. The production-grade versions add error handling and live at /integrations/laravel/production-usage/.

The facade resolves a fresh document from the container on each call. The container is Laravel’s service registry. This snippet matches the behavior that tests/Unit/Laravel/Facades/PdfTest.php asserts.

resource: src/Laravel/Facades/Pdf.php + PdfTest.php
<?php
declare(strict_types=1);
use NextPDF\Laravel\Facades\Pdf;
Pdf::addPage();
Pdf::cell(0, 10, 'Hello from Laravel', newLine: true);
Pdf::save(storage_path('app/hello.pdf'));

PdfResponse::download() returns an Illuminate\Http\Response with Content-Type: application/pdf, an attachment disposition, and Open Worldwide Application Security Project (OWASP) security headers. tests/Unit/Laravel/Http/PdfResponseTest.php checks the status code, content type, disposition prefix, and headers.

resource: src/Laravel/Http/PdfResponse.php + PdfResponseTest.php
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Http\Response;
use NextPDF\Contracts\PdfDocumentInterface;
use NextPDF\Laravel\Http\PdfResponse;
final class ReportController extends Controller
{
public function download(): Response
{
$document = app(PdfDocumentInterface::class);
$document->addPage();
$document->cell(0, 10, 'Monthly report', newLine: true);
return PdfResponse::download($document, 'report.pdf');
}
}

To show an inline browser preview, swap download() for inline(). For large documents, use streamInline() or streamDownload(). They send the PDF in deterministic 64 KB chunks.

GeneratePdfJob builds and saves a PDF on a queue worker. The builder closure receives the document resolved from the container and returns the configured document. tests/Unit/Laravel/Jobs/GeneratePdfJobTest.php confirms that the job creates the file at the exact output path.

resource: src/Laravel/Jobs/GeneratePdfJob.php + GeneratePdfJobTest.php
<?php
declare(strict_types=1);
use NextPDF\Contracts\PdfDocumentInterface;
use NextPDF\Laravel\Jobs\GeneratePdfJob;
GeneratePdfJob::dispatch(
storage_path('app/reports/january-2026.pdf'),
static fn (PdfDocumentInterface $document): PdfDocumentInterface => $document
->addPage()
->cell(0, 10, 'January report', newLine: true),
);

The output path must end in .pdf. The job validates the path on the worker before writing.

The production versions add explicit error handling, success and failure callbacks on the job, and a typed exception strategy. They are documented in full at /integrations/laravel/production-usage/.

  • The facade returns a different document instance for each resolution. Do not cache Pdf::getFacadeRoot() across logical documents.
  • If you pass an empty filename to any PdfResponse factory, it defaults to document.pdf. The response test suite asserts this default.
  • Non-ASCII filenames receive an RFC 5987 filename*= parameter automatically. ASCII names do not.
  • GeneratePdfJob rejects path traversal, stream wrappers, null bytes, and any non-.pdf extension. It throws InvalidArgumentException on the worker.

A single-page document generates well within the per-page wall budget listed in front matter. Moving generation to GeneratePdfJob removes PDF build time from the HTTP request entirely. The request returns once the job is dispatched.

PdfResponse factories apply a fixed OWASP header set. They also sanitize the download filename. The queued job validates its output path. Detailed threat coverage is available at /integrations/laravel/security-and-operations/.

No normative standard governs this tutorial. Every snippet is verified against the package source and the corresponding test under tests/.

Signed and PDF/A output is available with nextpdf/premium as an optional Enterprise capability. The Core package documented here needs no code change to adopt it. See https://nextpdf.dev/get-license/?intent=laravel-signing.

  • /integrations/laravel/install/ — install and publish configuration
  • /integrations/laravel/production-usage/ — controller and job wired with dependency injection and error handling
  • /integrations/laravel/configuration/ — configuration keys used here
  • /integrations/laravel/overview/ — architecture and binding lifetimes