0

Deferred providers — loading only when needed

Advanced5 min read·lv-03-003
laravel-srcperformance

Concept

Deferred service providers load their bindings only when a bound class is actually needed, rather than on every request. This reduces bootstrap time for applications with many providers where only a subset of services are used per request.

How deferral works: A deferred provider implements the $defer property (Laravel ≤ 9) or the DeferrableProvider interface (Laravel 10+). It also declares provides(): array — the list of class names it registers. Laravel skips the provider's register() during bootstrap. Only when code calls app()->make(SomeClass::class) for one of the declared classes does Laravel load and register that provider.

DeferrableProvider interface: In Laravel 10+, implement Illuminate\Contracts\Support\DeferrableProvider. No $defer = true property needed. The interface signals deferral.

When to use deferred providers:

  • Services that are NOT used on most requests (background processing services, CLI-only services, rarely-used third-party integrations).
  • Heavy providers that perform significant work during register().

When NOT to use:

  • Services used on every request (auth, session, database, cache) — the check overhead doesn't pay off.
  • Services that need to run boot logic (event listeners, routes) on every request.

Important: Deferred providers only defer register(). boot() still runs on every request because boot-time actions (event listeners, routes) are needed globally.

Code Example

php
<?php
namespace App\Providers;

use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;

// Laravel 10+ — implement DeferrableProvider interface
class PdfServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        // This register() runs ONLY when PdfGenerator is actually needed
        $this->app->singleton(\App\Services\PdfGenerator::class, function($app) {
            // Expensive: loads large library, connects to external PDF service
            return new \App\Services\PdfGenerator(
                config('services.pdf.api_key'),
                config('services.pdf.endpoint'),
            );
        });

        $this->app->alias(\App\Services\PdfGenerator::class, 'pdf');
    }

    /**
     * Declare what this provider registers.
     * Laravel uses this to know when to load the provider.
     */
    public function provides(): array
    {
        return [
            \App\Services\PdfGenerator::class,
            'pdf',
        ];
    }
}
php
// config/app.php — register like any other provider
'providers' => [
    // ...
    App\Providers\PdfServiceProvider::class, // deferred — loaded only when PdfGenerator is needed
],
php
// Usage — PdfServiceProvider registers only when this line is hit
$pdf = app(\App\Services\PdfGenerator::class);
// or: app('pdf')
// or via injection: __construct(private readonly PdfGenerator $pdf) {}

// In most API responses where PDF is not needed — zero overhead from this provider