This page assumes familiarity with Laravel Package Development. Make sure you understand the fundamentals of service providers before reading on.
Why deferred providers matter
A typical service provider runsregister() and boot() on every request. Initializing mail, queues, cache, and other features that are not needed on every page is wasteful.
The DeferrableProvider interface
Illuminate\Contracts\Support\DeferrableProvider is a simple interface with a single method: provides().
Basic implementation
Implementing a deferred provider takes three steps.1
Implement DeferrableProvider
2
Register bindings in register()
Write your bindings in
register() just like a regular provider.3
Return registered services from provides()
provides() must return every service bound in register(). Laravel uses this list to determine which provider to load when a given service is requested.How the service manifest works
At boot time, Laravel generates a manifest file atbootstrap/cache/services.php. This file stores a mapping of all services provided by deferred providers.
Internal flow
The importance of provides()
If a binding is missing fromprovides(), that service will never be resolved.
$bindings / $singletons properties — every key must be included in provides().
Constraints of deferred providers
Deferred providers are designed solely for registering container bindings. Providers that do the following inboot() cannot be deferred.
The when() method — event-triggered loading
Thewhen() method lets you load a provider when a specific event fires, rather than only when a service is resolved. This is useful for providers that are only needed in certain contexts, such as job processing.
when() fires, the provider is loaded even if none of its services have been directly resolved.
Using deferred providers in packages
When distributing a third-party package, a deferred service provider directly benefits the performance of the user’s application.Recommended pattern
mergeConfigFrom() internally checks for a cached config, so it is safe to call inside a deferred provider’s register(). However, if config is already cached, it has no effect.Separating Artisan command registration with runningInConsole()
Command registration is only needed when Artisan is running, so guard it withrunningInConsole(). If you want to defer a provider that also registers commands, either include the command classes in provides() or create a separate provider for commands.
Deferred providers in Laravel core
Many of Laravel’s built-in providers are deferred, avoiding eager initialization of services that are not used on every request.
In an API-only application, providers like
MailServiceProvider and BroadcastServiceProvider may never be loaded at all during a request.
When to defer (and when not to)
Good candidates for deferral
Good candidates for deferral
- Services not used on every request (mailers, report generators, external API clients, etc.)
- Services requiring external connections or file I/O to initialize
- Services with a heavy object graph
- Providers that only register CLI commands
Poor candidates for deferral
Poor candidates for deferral
- Providers that register routes (e.g.,
loadRoutesFrom) - Providers that register always-on middleware or exception handlers
- Providers that register Eloquent global scopes or observers
- Lightweight services used on the majority of requests (deferred overhead may exceed the benefit)
Related pages
Laravel Package Development
A comprehensive guide to developing Laravel packages centered on service providers.
Package Versioning and Compatibility
Strategies for maintaining packages across major Laravel and PHP version upgrades.