Skip to content

Laravel developer guide

The Laravel package adapts NextPDF to Laravel conventions without changing the core document lifecycle. The container owns shared registries and factories. Each PDF document is disposable, so you should build, return, stream, or save it once.

Use this guide when you design application services, queue jobs, response flows, or test coverage for nextpdf/laravel.

LayerOwned byResponsibilityDo not put here
ControllerApplicationAuthorize the request, choose a document builder, and return a response.PDF layout rules shared across use cases.
Application serviceApplicationCollect domain data and call document-building code.Container boot logic or package configuration.
Document builderApplicationTranslate domain data into NextPDF document calls.Request objects, Eloquent query logic, or queue transport details.
Laravel integrationnextpdf/laravelBind factories, registries, signer, TSA client, facade, responses, and queue job.Business-specific storage paths or tenant policy.
Core enginenextpdf/nextpdfBuild and serialize the PDF.Laravel response, queue, or filesystem policy.
StageBehaviorDeveloper action
Service provider registrationNextPdfServiceProvider::register() registers shared registries, the document factory, the document binding, HTTP client, time-stamping authority (TSA) client, signer, and optional e-invoice contracts.Publish and review config/nextpdf.php before production.
Document resolutionThe Pdf facade and PdfDocumentInterface binding resolve a fresh document through DocumentFactoryInterface.Resolve a document once per request, command, or queued job.
AuthoringApplication code calls core document APIs through the facade or injected document.Keep domain data extraction outside the document builder.
Terminal outputPdfResponse emits HTTP output, or the document is saved to disk.Choose one terminal output path per document.
Queue executionGeneratePdfJob rebuilds the document in the worker and validates the output path again.Pass scalar context and keep callbacks idempotent.
PathPurpose
app/Pdf/Builders/*Pure document builders. They receive data and return a completed document.
app/Pdf/Data/*Small data transfer objects (DTOs) that carry already-authorized document input.
app/Services/*Application orchestration, queries, authorization handoff, and storage path selection.
app/Jobs/*Optional wrappers around GeneratePdfJob when the application needs named jobs.
tests/Feature/Pdf/*HTTP response, queue dispatch, and authorization tests.
tests/Unit/Pdf/*Builder tests with small deterministic input.

Keep builders independent of Laravel request objects. You should be able to call a builder from a controller, command, test, or queue worker with the same input.

<?php
namespace App\Pdf\Builders;
use App\Pdf\Data\InvoicePdfData;
use NextPDF\Contracts\PdfDocumentInterface;
final readonly class InvoicePdfBuilder
{
public function build(PdfDocumentInterface $pdf, InvoicePdfData $data): PdfDocumentInterface
{
$pdf->setTitle($data->title)
->addPage()
->setFont('dejavusans', '', 12)
->writeHtml($data->html);
return $pdf;
}
}

Use constructor injection when the PDF flow is part of application logic. Use the facade only for short controller flows where the static style is easier to read.

<?php
namespace App\Http\Controllers;
use App\Pdf\Builders\InvoicePdfBuilder;
use App\Pdf\Data\InvoicePdfData;
use NextPDF\Contracts\PdfDocumentInterface;
use NextPDF\Laravel\Http\PdfResponse;
final readonly class DownloadInvoiceController
{
public function __invoke(
PdfDocumentInterface $pdf,
InvoicePdfBuilder $builder,
) {
$document = $builder->build(
$pdf,
InvoicePdfData::fromInvoiceId(1234),
);
return PdfResponse::download($document, 'invoice-1234.pdf');
}
}

Response helpers materialize the document bytes before they build the Laravel response. They are response helpers, not background renderers.

GeneratePdfJob accepts a builder callable and an output path. The job validates unsafe paths at execution time. Application code should still choose a tenant-safe storage root before dispatch.

<?php
use App\Pdf\Builders\QueuedInvoiceBuilder;
use NextPDF\Laravel\Jobs\GeneratePdfJob;
GeneratePdfJob::dispatch(
outputPath: storage_path('app/pdfs/invoice-1234.pdf'),
builder: [QueuedInvoiceBuilder::class, 'build'],
)->onQueue(config('nextpdf.queue.queue', 'pdf'));

Keep queue callbacks small. Prefer writing durable state from an application job listener instead of storing complex closures in the queue payload.

Extension pointUse it forConstraint
PdfDocumentInterface bindingReplace or decorate document creation for application-wide defaults.Must return a fresh document instance.
DocumentFactoryInterfaceCreate fresh documents explicitly in services and tests.Do not cache returned documents.
config/nextpdf.phpDefaults, queue settings, Chrome renderer settings, signing hooks, TSA, OCSP cache.Treat environment variables as deployment config, not request input.
GeneratePdfJob builderBuild documents asynchronously.The callable must be serializable by Laravel’s queue transport.
Success/failure callbacksPost-generation notification or cleanup.Keep callbacks idempotent and side-effect aware.
Optional Premium contractsE-invoice embedder, validator, profile, and Schematron runner.Resolve only where the optional package is installed and licensed.
  1. Build the first document synchronously in a controller or feature test.
  2. Move layout code into a builder class under app/Pdf/Builders.
  3. Move query and authorization logic into an application service.
  4. Add PdfResponse tests for headers and filenames.
  5. Move slow or high-volume generation to GeneratePdfJob.
  6. Add queue tests for serialized context, output path policy, and failure handling.
  7. Measure memory and render time with representative production data.
FailureWhere it should be handledRecommended response
Invalid request or unauthorized documentController or policy.Return the application’s normal authorization or validation response.
Missing font or invalid imageBuilder test and application logging.Fail the request or job; do not emit partial PDFs.
Unsafe output pathApplication storage service and GeneratePdfJob.Reject before dispatch and rely on worker-side validation as defense in depth.
Signing or TSA failureSigning service boundary.Decide whether the document may be unsigned; default to fail closed for regulated documents.
Queue timeoutQueue worker configuration and observability.Retry only when the builder is deterministic and output path is safe to overwrite.
ConcernDefaultWhen to override
Queue namepdfUse a dedicated queue when generation competes with user-facing jobs.
Job timeout120 secondsIncrease only after measuring document size and worker capacity.
Response filenamedocument.pdfUse sanitized business identifiers.
Font registryShared and locked after warmup.Add preload_fonts for fonts used on hot paths.
Image registryShared bounded cache.Lower image_cache_mb for memory-constrained workers.
Streamed response chunking64 KB chunks.Do not depend on chunk boundaries; they are an output detail.
  • Controller tests assert Content-Type, Content-Disposition, and defensive headers.
  • Builder tests use deterministic DTOs and do not query the database.
  • Queue tests assert the builder receives a fresh document.
  • Path tests cover traversal, stream-wrapper, null-byte, and non-.pdf rejection.
  • Worker tests render representative documents under the same memory limit as production.
  • Optional signing tests cover missing certificate, invalid password, TSA unavailable, and configured signature level.