NextPDF Laravel integration overview
At a glance
Section titled “At a glance”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.
Install
Section titled “Install”composer require nextpdf/laravelThe 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/.
Conceptual overview
Section titled “Conceptual overview”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.
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.
API surface
Section titled “API surface”| Class | Public entry point | Returns | Purpose |
|---|---|---|---|
NextPdfServiceProvider | register(), boot(), provides() | void / array | Container bindings, config publish, deferred entry list |
Facades\Pdf | static proxy (addPage(), cell(), save(), …) | static / mixed | Resolves PdfDocumentInterface per call |
Http\PdfResponse | inline(), download(), streamInline(), streamDownload() | Response / StreamedResponse | HTTP responses with Open Worldwide Application Security Project (OWASP) headers |
Jobs\GeneratePdfJob | dispatch(), handle(), then(), catch(), failed() | PendingDispatch / void / self | Queued PDF generation |
Container keys bound by the provider:
| Key | Lifetime | Resolves to |
|---|---|---|
NextPDF\Contracts\FontRegistryInterface (alias FontRegistry) | singleton, locked | NextPDF\Typography\FontRegistry |
NextPDF\Graphics\ImageRegistry | singleton, LRU-bounded | ImageRegistry |
NextPDF\Contracts\DocumentFactoryInterface (alias DocumentFactory) | singleton | NextPDF\Core\DocumentFactory |
Psr\Http\Client\ClientInterface | singleton | SecurityAwareHttpClient wrapping CurlHttpClient |
NextPDF\Security\Timestamp\TsaClient | scoped | TsaClient or null when no timestamp authority (TSA) URL |
NextPDF\Contracts\SignerInterface | factory | DigitalSigner or null when signing disabled |
NextPDF\Contracts\PdfDocumentInterface (alias nextpdf) | factory | NextPDF\Core\Document |
NextPDF\Contracts\EInvoice\{Embedder,Validator,Profile,SchematronRunner}Interface | factory | resolves only when nextpdf/premium is installed |
Code sample — Quick start
Section titled “Code sample — Quick start”<?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/.
Code sample — Production
Section titled “Code sample — Production”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/.
<?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');Edge cases & gotchas
Section titled “Edge cases & gotchas”- 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. SignerInterfaceandTsaClientresolve tonullby 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/premiumis 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 byPdf::clearResolvedInstances(): the calls operate on different documents.
Performance
Section titled “Performance”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.
Security notes
Section titled “Security notes”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/.
Conformance
Section titled “Conformance”| Claim | Source | Clause | reference_id |
|---|---|---|---|
| Container resolution / lifetime semantics | PSR-11 Container | §1.1.2 | |
| PSR-4 autoload prefix mapping | PSR-4 Autoloader | §3 |
Commercial context
Section titled “Commercial context”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.
See also
Section titled “See also”- /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