0

Service providers — the backbone of Laravel's bootstrap

Intermediate5 min read·lv-03-001
interviewlaravel-src

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:

  1. Bind classes into the IoC container (register dependencies, interfaces to implementations, singletons).
  2. Bootstrap application-wide behavior (register event listeners, middleware, routes, macros, view composers).
  3. 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
<?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]);
        });
    }
}
php
// 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,
],