Service providers — the backbone of Laravel's bootstrap
Concept
Service providers are the central place for bootstrapping a Laravel application. Every core Laravel feature (routing, cache, session, database, validation, filesystem, etc.) is registered via a service provider. When the application boots, it loads all providers listed in config/app.php's providers array.
What service providers do:
- Bind classes into the IoC container (register dependencies, interfaces to implementations, singletons).
- Bootstrap application-wide behavior (register event listeners, middleware, routes, macros, view composers).
- Load resources (load routes from files, register config files, load translations, publish assets).
Every provider has two lifecycle methods:
register(): Only bind things into the service container. Nothing else — no access to other services, no event listening. The container isn't fully populated yet.boot(): Called after ALL providers have been registered. Safe to depend on other services, register routes, attach event listeners, extend Blade.
The providers array in config/app.php: Lists all providers to load. Order matters for some edge cases (a provider loaded later can override bindings from an earlier one). Framework providers always load first.
Package providers: Third-party packages use the extra.laravel.providers key in composer.json to auto-register their provider via Package Auto-discovery (Laravel 5.5+). No manual registration needed.
Code Example
<?php
// app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Contracts\PaymentGateway;
use App\Services\StripeGateway;
class AppServiceProvider extends ServiceProvider
{
/**
* Register IoC bindings.
* ONLY container bindings here — no event listeners, no routes.
*/
public function register(): void
{
$this->app->singleton(PaymentGateway::class, function($app) {
return new StripeGateway(
config('services.stripe.key'),
config('services.stripe.secret'),
);
});
$this->app->bind(
\App\Contracts\UserRepository::class,
\App\Repositories\EloquentUserRepository::class,
);
}
/**
* Bootstrap application services.
* All providers are registered — safe to depend on any binding.
*/
public function boot(): void
{
// Register view composer
\Illuminate\Support\Facades\View::composer('layouts.app', function($view) {
$view->with('notifications', auth()->user()?->unreadNotifications()->count() ?? 0);
});
// Register a macro on the Response class
\Illuminate\Http\Response::macro('apiSuccess', function(mixed $data) {
return response()->json(['success' => true, 'data' => $data]);
});
}
}// config/app.php — provider order
'providers' => [
// Laravel Framework providers (first)
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
// ... more framework providers ...
// Application providers (after framework)
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
],