Service Providers showed every register() finishing before any boot(), hence the rule: register() only binds, and boot() does the rest (listeners, view composers, gates, macros). A provider that only binds can be deferred:
class PaymentServiceProvider extends ServiceProvider implements DeferrableProvider
{
public array $singletons = [PaymentGateway::class => FakeGateway::class];
public function provides(): array
{
return [PaymentGateway::class];
}
}provides() lands in bootstrap/cache/services.php, and the provider is not even constructed until something asks for PaymentGateway. A route that checks app()->getLoadedProviders() before and after app(PaymentGateway::class) returned:
$ curl -s http://127.0.0.1:8000/providers before make(): deferred; after make(): loaded
Deferral helps only on web requests: the console kernel calls loadDeferredProviders() at bootstrap, so artisan and tinker load every provider first. Packages list providers under extra.laravel.providers, which package:discover loads automatically.