Zum Hauptinhalt springen
Beim Start von Laravel werden registrierte Service Provider auch dann geladen, wenn deren Funktionalität während einer Anfrage nie genutzt wird. Deferred Service Provider lösen dieses Problem, indem sie das Laden bis zur tatsächlichen Nutzung des Services aufschieben.
Diese Seite setzt Wissen aus Grundlagen der Paketentwicklung voraus. Es empfiehlt sich, zunächst die grundlegende Funktionsweise von Service Providern zu verstehen.

Warum Deferred Provider nötig sind

Ein gewöhnlicher Service Provider ruft bei jeder Anfrage register() und boot() auf. Es ist Verschwendung, Funktionen wie Mail-Versand, Queue oder Cache jedes Mal zu initialisieren, obwohl sie auf vielen Seiten gar nicht gebraucht werden.
// Für diesen Provider wird bei jedem Request register() aufgerufen
class ReportServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Bindet den schwergewichtigen Report-Service jedes Mal
        $this->app->singleton(ReportGenerator::class, function ($app) {
            return new ReportGenerator(
                $app->make(PdfRenderer::class),
                $app->make(ChartRenderer::class),
                $app->make(DataExporter::class),
            );
        });
    }
}
Wenn Sie diesen Provider deferren, wird er nur bei Anfragen initialisiert, die tatsächlich einen Report erzeugen.

Das Interface DeferrableProvider

Illuminate\Contracts\Support\DeferrableProvider ist ein schlichtes Interface mit einer einzigen Methode provides().
namespace Illuminate\Contracts\Support;

interface DeferrableProvider
{
    public function provides();
}
Sobald Sie dieses Interface implementieren, arbeitet Ihr Provider im Deferred-Modus.

Grundlegende Implementierung

Die Implementierung erfolgt in drei Schritten.
1

DeferrableProvider implementieren

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

class ReportServiceProvider extends ServiceProvider implements DeferrableProvider
{
    // ...
}
2

Services in register() binden

Bindungen tragen Sie wie in einem normalen Provider in register() ein.
public function register(): void
{
    $this->app->singleton(ReportGenerator::class, function ($app) {
        return new ReportGenerator(
            $app->make(PdfRenderer::class),
            $app->make(ChartRenderer::class),
            $app->make(DataExporter::class),
        );
    });

    $this->app->singleton(ReportRepository::class, function ($app) {
        return new ReportRepository($app->make('db'));
    });
}
3

Aus provides() die registrierten Services zurückgeben

provides() muss alle Services zurückgeben, die Sie in register() gebunden haben. Laravel bestimmt anhand dieser Liste, „bei welchem Service dieser Provider zu laden ist”.
public function provides(): array
{
    return [
        ReportGenerator::class,
        ReportRepository::class,
    ];
}

Funktionsweise des Service-Manifests

Beim Start erzeugt Laravel eine Manifest-Datei bootstrap/cache/services.php. Dort ist die Liste der Services aller Deferred Provider hinterlegt.
// Beispiel bootstrap/cache/services.php (automatisch generiert)
return [
    'providers' => [
        // Dieselbe Liste wie in bootstrap/providers.php
    ],
    'eager' => [
        // Sofort geladene Provider
        App\Providers\AppServiceProvider::class,
    ],
    'deferred' => [
        // Mapping Servicename => Provider-Klasse
        'App\Services\ReportGenerator' => ReportServiceProvider::class,
        'App\Repositories\ReportRepository' => ReportServiceProvider::class,
        'cache'     => Illuminate\Cache\CacheServiceProvider::class,
        'cache.store' => Illuminate\Cache\CacheServiceProvider::class,
        'queue'     => Illuminate\Queue\QueueServiceProvider::class,
    ],
    'when' => [],
];
Anhand dieses Manifests weiß Laravel, „welcher Provider einen Service anbietet”, ohne die Dateien selbst zu laden. Der tatsächliche Provider wird erst dann geladen, wenn der Service zum ersten Mal aufgelöst wird.
Nach dem Hinzufügen oder Ändern eines Providers regenerieren Sie das Manifest.
php artisan optimize:clear
# oder
php artisan clear-compiled

Ablauf der internen Verarbeitung


Bedeutung der Methode provides()

Vergessen Sie einen Eintrag in provides(), wird der betroffene Service nie aufgelöst.
public function register(): void
{
    $this->app->singleton(ReportGenerator::class, fn ($app) => new ReportGenerator());

    // Zusätzliches Binding
    $this->app->singleton('report', fn ($app) => $app->make(ReportGenerator::class));
}

public function provides(): array
{
    return [
        ReportGenerator::class,
        'report',  // ← Auch bei String-Keys nicht vergessen
    ];
}
Auch wenn Sie die Properties $bindings / $singletons verwenden, listen Sie sie in provides() auf.
class AnalyticsServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public $singletons = [
        AnalyticsClient::class => DefaultAnalyticsClient::class,
    ];

    public function provides(): array
    {
        // Alle Keys aus $singletons wiederholen
        return [
            AnalyticsClient::class,
        ];
    }
}

Grenzen von Deferred Providern

Deferred Provider eignen sich für Provider, die ausschließlich Bindings im Container registrieren. Provider, die in boot() z. B. Folgendes machen, dürfen nicht deferred werden.
EinschränkungGrund
Route-RegistrierungRouten werden beim Anwendungsstart aufgelöst — im Deferred-Modus funktioniert das nicht
Registrierung globaler MiddlewareMuss vor der Request-Verarbeitung erfolgen
Registrierung von Event-Listenern (dauerhaft benötigt)Muss vor dem Event feuern registriert sein
Hinzufügen von Blade-DirektivenMuss vor dem Kompilieren der Views erfolgen
Sie dürfen bei Deferred Providern zwar eine boot()-Methode schreiben, aber deren Inhalt läuft erst, wenn der Service aufgelöst wird. Erledigen Sie in boot() „stets erforderliche” Aufgaben wie Routen oder Middleware, kommt es zu unerwartetem Verhalten.

when() — Registrierung per Event-Trigger

Mit der Methode when() können Sie den Provider laden lassen, sobald ein bestimmtes Event feuert. Praktisch für Provider, die nur in bestimmten Kontexten (z. B. Job-Verarbeitung) benötigt werden.
class ReportServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->app->singleton(ReportGenerator::class, fn () => new ReportGenerator());
    }

    public function provides(): array
    {
        return [ReportGenerator::class];
    }

    /**
     * Nicht nur beim Auflösen eines Services,
     * sondern auch beim Feuern bestimmter Events wird der Provider geladen.
     */
    public function when(): array
    {
        return [
            \App\Events\ReportRequested::class,
        ];
    }
}
Feuert eines der zurückgegebenen Events, wird der Provider geladen — auch wenn der Service noch nicht aufgelöst wurde.

Nutzen in der Paketentwicklung

Auch bei Drittanbieter-Paketen tragen Deferred Provider zur Performance der Nutzer-Anwendung bei.

Empfohlenes Muster

namespace Acme\Analytics;

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

class AnalyticsServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->mergeConfigFrom(__DIR__.'/../config/analytics.php', 'analytics');

        $this->app->singleton(AnalyticsManager::class, function ($app) {
            return new AnalyticsManager($app->make('config')->get('analytics'));
        });

        $this->app->singleton('analytics', fn ($app) => $app->make(AnalyticsManager::class));
    }

    public function boot(): void
    {
        // boot() nur für Publish-Registrierungen nutzen
        if ($this->app->runningInConsole()) {
            $this->publishes([
                __DIR__.'/../config/analytics.php' => config_path('analytics.php'),
            ], 'analytics-config');
        }
    }

    public function provides(): array
    {
        return [
            AnalyticsManager::class,
            'analytics',
        ];
    }
}
mergeConfigFrom() prüft intern, ob die Konfiguration gecacht ist. Der Aufruf innerhalb von register() eines Deferred Providers ist daher sicher. Bei gecachter Konfiguration passiert allerdings nichts.

Artisan-Commands mit runningInConsole() abtrennen

Command-Registrierung ist nur beim Artisan-Start nötig — trennen Sie sie mit runningInConsole(). Wenn Sie einen Provider deferren, der Commands anbietet, listen Sie die Command-Klassen auch in provides() oder stellen Sie einen separaten Command-Provider bereit.
public function boot(): void
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            AnalyticsFlushCommand::class,
        ]);
    }
}

Verwendung im Laravel-Kern

Viele der Kern-Provider von Laravel sind Deferred Provider. So werden Services, die nicht bei jedem Request gebraucht werden, nicht sofort geladen.
ProviderBereitgestellte Services
CacheServiceProvidercache, cache.store, RateLimiter
QueueServiceProviderqueue, queue.worker, queue.failer
MailServiceProvidermail.manager, mailer
RedisServiceProviderredis, redis.connection
HashServiceProviderhash, hash.driver
ValidationServiceProvidervalidator, validation.presence
TranslationServiceProvidertranslator
BroadcastServiceProviderBroadcast
In reinen API-Anwendungen kommt es vor, dass MailServiceProvider oder BroadcastServiceProvider während eines Requests nie geladen werden.

Entscheidungskriterien für Deferring

  • Services, die nicht in jedem Request genutzt werden (Mail, Reports, externe API-Clients)
  • Services, deren Initialisierung externe Verbindungen oder Dateizugriffe erfordert
  • Services mit schweren Objekt-Graphen
  • Provider, die nur in der CLI verwendete Commands liefern
  • Provider, die Routen registrieren (loadRoutesFrom usw.)
  • Provider, die dauerhaft aktive Middleware oder Exception-Handler registrieren
  • Provider, die globale Eloquent-Scopes oder Observer registrieren
  • Leichte Services, die in den meisten Requests genutzt werden (Overhead des Deferrings überwiegt)

Verwandte Seiten

Grundlagen der Paketentwicklung

Erläutert die Entwicklung von Laravel-Paketen rund um Service Provider.

Versionskompatibilität von Paketen verwalten

Erläutert Wartungsstrategien für Pakete bei Major-Upgrades von Laravel und PHP.
Zuletzt geändert am 13. Juli 2026