0

Service provider — the bootstrap unit that registers things into the container

Beginner5 min read·eng-14-004
interviewlaravel-src

Definition

A service provider is a class that acts as the bootstrap unit of a Laravel application — it is where you register bindings into the service container, configure services, and hook into the application lifecycle. Every feature of Laravel (routing, database, queue, mail, cache) is registered via a service provider. Your application-specific providers live in app/Providers/; framework providers live in vendor/laravel/framework/src/Illuminate/*/ServiceProvider.php. A provider has two lifecycle methods: register() (for container bindings, runs before boot) and boot() (for anything that needs other services already bound, runs after all providers have registered).

In Practice

php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Contracts\PaymentGateway;
use App\Services\StripeGateway;
use App\Services\CurrencyConverter;

class PaymentServiceProvider extends ServiceProvider
{
    // register() — only container bindings here
    // Other services may not be ready yet during register()
    public function register(): void
    {
        $this->app->singleton(PaymentGateway::class, function ($app) {
            return new StripeGateway(
                config('services.stripe.secret'),
                $app->make(CurrencyConverter::class),
            );
        });
    }

    // boot() — everything else: event listeners, route macros, view composers
    // All providers have finished register() before any boot() runs
    public function boot(): void
    {
        $this->loadRoutesFrom(__DIR__.'/../routes/payment.php');
        $this->publishes([
            __DIR__.'/../config/payment.php' => config_path('payment.php'),
        ]);
    }
}

Service providers are listed in config/app.php under the providers key, or (in newer Laravel) auto-discovered via the extra.laravel.providers key in composer.json. The framework bootstraps them in two passes: first calling register() on every provider, then calling boot() on every provider. This two-pass design is what guarantees that when your boot() runs, every binding from every other provider is already available.

In Context

In interviews, service providers are often asked about in the context of the Laravel request lifecycle. The correct answer is: providers are loaded during the bootstrap phase, before any route is matched or any controller runs. The kernel calls Application::boot() which fires both passes across all registered providers.

The common confusion is putting code that uses other services inside register(). If you call app(Mailer::class) inside register(), you may trigger resolution before that class's own provider has run, causing a binding resolution exception. The rule is strict: register() only binds; boot() uses.

Deferred providers are an optimization: the provider declares which bindings it provides via a provides() method, and Laravel skips loading the provider entirely until one of those bindings is actually resolved. This is how Laravel keeps the bootstrap fast — only the providers that are actually needed for a given request are fully loaded.