NextPDF Laravel boot and auto-discovery
At a glance
Section titled “At a glance”Laravel auto-discovers NextPdfServiceProvider from the package
composer.json. The provider registers deferred container bindings and,
in console context, publishes the configuration file. This page explains
how discovery works and how long each binding lives.
Install
Section titled “Install”composer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-configHow Laravel auto-discovery works
Section titled “How Laravel auto-discovery works”The package declares its provider and facade alias in the
extra.laravel block of its own composer.json:
{ "extra": { "laravel": { "providers": [ "NextPDF\\Laravel\\NextPdfServiceProvider" ], "aliases": { "Pdf": "NextPDF\\Laravel\\Facades\\Pdf" } } }}When you run composer require, Laravel reads this block, then registers
the provider and alias. You do not need to edit config/app.php or
bootstrap/providers.php manually. The extra.laravel.providers array
auto-registers service providers, and extra.laravel.aliases
auto-registers facade aliases (Laravel 12 package development guide,
https://laravel.com/docs/12.x/packages, retrieved 2026-05-18).
Boot sequence
Section titled “Boot sequence”NextPdfServiceProvider implements DeferrableProvider and the standard
register() / boot() lifecycle.
register()merges the package config under thenextpdfkey. It then binds the container entries: font registry, image registry, document factory, PHP Standards Recommendation 18 (PSR-18) Hypertext Transfer Protocol (HTTP) client, timestamp client, signer, document, and e-invoice contracts. Every binding is a closure, so nothing heavy is constructed here.boot()checks that thembstringandzlibPHP extensions are loaded. It registers the publishable config under thenextpdf-configtag only whenrunningInConsole()is true.
Because the provider is deferred, register() runs only when you resolve
one of the entries returned by provides(). Resolving an unrelated
container key does not boot NextPDF.
Container bindings and lifetimes
Section titled “Container bindings and lifetimes”PHP Standards Recommendation 11 (PSR-11) permits two successive get()
calls with the same identifier to return different values depending on
the binding strategy (PSR-11 §1.1.2).
The provider relies on this behavior by design:
| Binding key | Lifetime | Notes |
|---|---|---|
FontRegistryInterface (+ FontRegistry alias) | singleton, locked after warmup | Warmed from preload_fonts; locked so no request can mutate it |
ImageRegistry | singleton | Bounded least recently used (LRU) cache sized by image_cache_mb; not locked |
DocumentFactoryInterface (+ DocumentFactory alias) | singleton | Stateless; shares the two registries |
Psr\Http\Client\ClientInterface | singleton | Request-forgery-aware client wrapping a curl client; built from tsa.* |
TsaClient | scoped | null when tsa.url is empty |
SignerInterface | factory | null when signing disabled or certificate empty |
PdfDocumentInterface (+ nextpdf alias) | factory | Fresh NextPDF\Core\Document per resolve, with default metadata applied |
EmbedderInterface, ValidatorInterface, ProfileInterface, SchematronRunnerInterface | factory | Resolve to Premium concretes; error on first resolve without nextpdf/premium |
The document binding applies defaults.creator, defaults.language,
and, when non-empty, defaults.author to each fresh document. When
pdfa is non-null, it enables PDF/A (Premium). When the artisan
section is present and a Chrome browser-factory class exists, it applies
the Chrome renderer config.
has() on the container takes a single string identifier (PSR-11 §1.1.2).
The e-invoice contracts are bound, so has() returns true for them even
when Premium is absent. The missing concrete only errors at
construction.
Disabling auto-discovery
Section titled “Disabling auto-discovery”Add the package to the application’s dont-discover array, then register
the provider manually:
{ "extra": { "laravel": { "dont-discover": ["nextpdf/laravel"] } }}<?php
declare(strict_types=1);
return [ App\Providers\AppServiceProvider::class, NextPDF\Laravel\NextPdfServiceProvider::class,];Configuration resolution order
Section titled “Configuration resolution order”Each key resolves in this order: environment variable → published
config/nextpdf.php value → package default merged at register().
Most keys accept either a NEXTPDF_* name or a legacy TCPDF_*
environment name. Prefer NEXTPDF_*.
Diagnostics
Section titled “Diagnostics”php artisan package:discover --ansiA line that lists nextpdf/laravel confirms discovery. Because the
provider is deferred, the bindings themselves do not appear until the
first resolve. The discovery line is the correct success signal.
Edge cases & gotchas
Section titled “Edge cases & gotchas”- The config publish registers only in console context, so a web-only
request never triggers it. Run
vendor:publishfrom the command-line interface (CLI). - Alongside the registry, factory, HTTP client, signer, timestamp, and
document keys,
provides()includes the four e-invoice contract keys. - A fresh install can look inert until the first relevant resolve. This is the deferred-provider design, not a fault.
Performance
Section titled “Performance”register() is O(1) because it creates closures only. The font registry
warmup is O(f) in preloaded fonts and runs once per worker process.
Deferring the provider keeps NextPDF construction cost off the framework
boot path until a binding is actually used.
Security notes
Section titled “Security notes”The deferred design narrows the attack surface at boot. The locked font registry prevents one request from changing font state for another in long-lived workers. For full threat coverage, see /integrations/laravel/security-and-operations/.
Conformance
Section titled “Conformance”| Claim | Source | Clause | reference_id |
|---|---|---|---|
| Successive resolutions may differ by binding strategy | PSR-11 Container | §1.1.2 | |
has() takes one string identifier | PSR-11 Container | §1.1.2 |
The official Laravel 12 package documentation corroborates the Laravel
discovery key names (https://laravel.com/docs/12.x/packages,
retrieved 2026-05-18).
Commercial context
Section titled “Commercial context”Premium concretes resolve through the same deferred binding keys. This optional Enterprise capability needs no code change in the Core package documented here. See https://nextpdf.dev/get-license/?intent=laravel-signing.
See also
Section titled “See also”- /integrations/laravel/install/ — install and publish
- /integrations/laravel/overview/ — package architecture
- /integrations/laravel/integration/ — end-to-end wiring how-to
- /integrations/laravel/configuration/ — every config key