Skip to content

NextPDF Laravel integration overview

The nextpdf/laravel package connects the NextPDF PDF engine to your Laravel 12 application and registers the container bindings for you. It includes a Pdf facade, a PdfResponse HTTP helper, and a queued GeneratePdfJob. Laravel auto-discovers the package, so you do not need to register it manually.

Terminal window
composer require nextpdf/laravel

The Composer constraint is nextpdf/core: ^3.0 || ^5.2. The package also requires laravel/framework: ^12.0 and php: >=8.4 <9.0. For the complete procedure, including configuration publishing and optional extensions, see /integrations/laravel/install/.

The package sits between the Laravel service container and the framework-agnostic NextPDF core. It does not reimplement PDF generation. Instead, it adapts the core NextPDF\Core\Document model to Laravel’s lifecycle, configuration, queues, and HTTP layer.

The diagram below traces a request from your application code through the package and into the shared core registries.

NextPDF Laravel request and render flowA request resolves a fresh document from the container, which the package adapts onto the shared font and image registries before HTTP or queue output.

Your Laravel app

Pdf facade

Laravel service container

NextPdfServiceProvider (deferred)

DocumentFactory (singleton)

Document (fresh per resolve)

FontRegistry (singleton, locked)

ImageRegistry (singleton, LRU)

PdfResponse (HTTP)

GeneratePdfJob (queue worker)

NextPDF Laravel request and render flow

The autoload map has one PSR-4 entry. PSR-4 is the PHP Standard Recommendation for autoloading, and its prefix NextPDF\Laravel\ maps to src/Laravel/. Under PSR-4, a namespace prefix corresponds to a base directory, and the remaining class name maps to a file path under that directory (PSR-4 §3). Four production classes live under this prefix:

  • NextPDF\Laravel\NextPdfServiceProvider — registers bindings and publishes the configuration.
  • NextPDF\Laravel\Facades\Pdf — a static proxy that resolves a fresh document from the container.
  • NextPDF\Laravel\Http\PdfResponse — creates inline, download, and streamed PDF responses with a fixed security-header set.
  • NextPDF\Laravel\Jobs\GeneratePdfJob — a queueable job that builds and saves a PDF on a worker.

The service provider implements DeferrableProvider, so it registers its bindings only when you resolve one of the advertised entries. This deferral keeps the framework boot path lean. The provider’s provides() method lists the deferred entries, and the container reads this list to map each key back to the provider.

Resolution follows the container contract: when a binding is present, resolving the identifier returns the registered entry. PSR-11 is the PHP Standard Recommendation for container interoperability, and it notes that two successive get() calls with the same identifier may return different values, depending on the binding strategy (PSR-11 §1.1.2). NextPDF relies on this behavior intentionally. Registries are singletons, so each resolve returns the same instance. Documents are factory-bound, so each resolve returns a fresh instance. For the full binding-lifetime table, see /integrations/laravel/boot-and-discovery/.

The architecture is designed for long-lived workers, such as Octane, RoadRunner, and Swoole. The font registry is a process-lifetime singleton: the package warms it once and then locks it, so no request can change shared font state. The image registry is a process-lifetime singleton with a bounded least-recently-used (LRU) cache. Because the package always creates each document from DocumentFactory, per-request mutable state never leaks across requests.

ClassPublic entry pointReturnsPurpose
NextPdfServiceProviderregister(), boot(), provides()void / arrayContainer bindings, config publish, deferred entry list
Facades\Pdfstatic proxy (addPage(), cell(), save(), …)static / mixedResolves PdfDocumentInterface per call
Http\PdfResponseinline(), download(), streamInline(), streamDownload()Response / StreamedResponseHTTP responses with Open Worldwide Application Security Project (OWASP) headers
Jobs\GeneratePdfJobdispatch(), handle(), then(), catch(), failed()PendingDispatch / void / selfQueued PDF generation

Container keys bound by the provider:

KeyLifetimeResolves to
NextPDF\Contracts\FontRegistryInterface (alias FontRegistry)singleton, lockedNextPDF\Typography\FontRegistry
NextPDF\Graphics\ImageRegistrysingleton, LRU-boundedImageRegistry
NextPDF\Contracts\DocumentFactoryInterface (alias DocumentFactory)singletonNextPDF\Core\DocumentFactory
Psr\Http\Client\ClientInterfacesingletonSecurityAwareHttpClient wrapping CurlHttpClient
NextPDF\Security\Timestamp\TsaClientscopedTsaClient or null when no timestamp authority (TSA) URL
NextPDF\Contracts\SignerInterfacefactoryDigitalSigner or null when signing disabled
NextPDF\Contracts\PdfDocumentInterface (alias nextpdf)factoryNextPDF\Core\Document
NextPDF\Contracts\EInvoice\{Embedder,Validator,Profile,SchematronRunner}Interfacefactoryresolves only when nextpdf/premium is installed
resource: README.md Quick Start (verified against src/Laravel/Facades/Pdf.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'));

For a runnable example scoped to a controller, see /integrations/laravel/quickstart/.

The production pattern resolves the document contract from the container rather than the facade, which keeps the call site explicit and testable. For the full controller, including dependency injection (DI) and error handling, see /integrations/laravel/production-usage/.

resource: src/Laravel/Http/PdfResponse.php (download factory)
<?php
declare(strict_types=1);
use NextPDF\Contracts\PdfDocumentInterface;
use NextPDF\Laravel\Http\PdfResponse;
$document = app(PdfDocumentInterface::class);
$document->addPage();
$document->cell(0, 10, 'Invoice', newLine: true);
return PdfResponse::download($document, 'invoice.pdf');
  • The provider is deferred, so resolving an unrelated container key does not boot NextPDF. The bindings appear only when you request one of the provides() entries.
  • SignerInterface and TsaClient resolve to null by design when you have not configured signing or the timestamp authority. Your code must null-check the result; do not assume an instance exists.
  • The e-invoice contract bindings are always registered, but they resolve to Premium concretes that exist only when nextpdf/premium is installed. Resolving them without Premium raises a class-not-found error, and the error appears on first resolve, not at boot.
  • The facade returns a fresh document per resolution. Consider two Pdf:: static calls in the same request separated by Pdf::clearResolvedInstances(): the calls operate on different documents.

Provider registration runs in O(1) time. The provider binds closures and does not construct heavy objects, so construction cost is deferred to the first resolve. Font registry warmup runs in O(f) time, where f is the number of preloaded font files, and runs once per worker process. This amortizes first-request latency in long-lived workers. The per-page memory budget for this overview is recorded in the front-matter field performance_budget.

PdfResponse applies a fixed Open Worldwide Application Security Project (OWASP) header set. The set includes X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Content-Security-Policy: default-src 'none', X-Robots-Tag, and Referrer-Policy: no-referrer. GeneratePdfJob validates its output path on the worker side, which mitigates tampered serialized payloads. For the full threat model and deployment configuration, see /integrations/laravel/security-and-operations/.

ClaimSourceClausereference_id
Container resolution / lifetime semanticsPSR-11 Container§1.1.2
PSR-4 autoload prefix mappingPSR-4 Autoloader§3

When nextpdf/premium is installed, the same provider exposes more capabilities: digital signing (PAdES B-B), PDF/A archival, and e-invoice contract bindings. It exposes them through the same container keys, so the Core package documented here needs no code change to adopt these capabilities. For details, see https://nextpdf.dev/get-license/?intent=laravel-signing.

  • /integrations/laravel/install/ — installation procedure and optional extensions
  • /integrations/laravel/quickstart/ — runnable controller example
  • /integrations/laravel/configuration/ — every config key, verified against config/nextpdf.php
  • /integrations/laravel/production-usage/ — DI-wired controller, error handling, queueing
  • /integrations/laravel/boot-and-discovery/ — auto-discovery and binding lifetimes
  • /integrations/laravel/security-and-operations/ — threat model and deployment configuration