RegisterProviders instantiates every provider (the framework's, packages' via Composer 5,243 's extra.laravel key, and yours in bootstrap/providers.php) and calls register() on each; only then does BootProviders call each boot(). So register() should only bind into the container, while boot() may use anything. php artisan make:provider BookshopServiceProvider creates a class and appends it to bootstrap/providers.php:
public function register(): void
{
app('trace')('BookshopServiceProvider::register');
$this->app->singleton(ShippingPolicy::class, fn () => new ShippingPolicy(
config('bookshop.free_shipping_over'),
));
}
public function boot(): void
{
app('trace')('BookshopServiceProvider::boot');
View::share('currency', config('bookshop.currency'));
}The trace for a route that type-hints ShippingPolicy $policy shows both register() calls finishing before either boot() starts (excerpt):
4.32 ms RegisterProviders 5.25 ms AppServiceProvider::register 5.27 ms BookshopServiceProvider::register 5.31 ms BootProviders 5.97 ms AppServiceProvider::boot 6.00 ms BookshopServiceProvider::boot
A provider that only binds services can implement DeferrableProvider and list them in provides() to become deferred (Writing Service Providers).