Service Providers

The previous lesson introduced the service container and showed a manual interface binding — $this->app->bind(PaymentGateway::class, StripePaymentGateway::class); — without saying where that line of code actually belongs. The answer is service providers: the central, standardized place where Laravel itself, and your own application, bootstrap everything before a request is handled — binding things into the container, registering event listeners, publishing configuration files, and more. Every single feature Laravel offers is wired up through a service provider somewhere.

What Is a Service Provider?

A service provider is just a plain PHP class extending Laravel's base ServiceProvider class, with two methods Laravel calls automatically at specific points during the application's bootstrapping process: register() and boot(). Every provider your application uses is listed in the providers array of bootstrap/providers.php (or, in older Laravel versions, config/app.php), which is how Laravel knows which providers to load on every request.

register() vs. boot(): The Critical Difference

These two methods look similar but serve very different purposes, and mixing them up is one of the most common sources of confusing bugs for developers new to Laravel.

MethodPurposeImportant rule
register()ONLY for binding things into the service containerMust never depend on any other service already being available — other providers may not have registered yet
boot()General bootstrapping — event listeners, view composers, route model bindings, anything elseRuns after every provider's register() has already executed, so it's always safe to use any service here
Note: Laravel deliberately splits bootstrapping into two passes — register everything first, boot everything second — so that by the time any provider's boot() runs, every binding from every other provider is already guaranteed to be in place.

Generating a Custom Provider

Custom providers are generated with Artisan, which creates a new class inside app/Providers/ pre-filled with empty register() and boot() methods:

php artisan make:provider PaymentServiceProvider

Registering the Provider

A freshly generated provider does nothing until Laravel actually knows to load it. Recent Laravel versions add it to the array automatically, but it's worth knowing where that registration lives: bootstrap/providers.php.

<?php

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\PaymentServiceProvider::class,
];

Full Worked Example: Binding an Interface in register()

Here is the complete provider from start to finish, binding the same PaymentGateway interface introduced in Service Container & Dependency Injection to its concrete StripePaymentGateway implementation:

<?php

namespace App\Providers;

use App\Contracts\PaymentGateway;
use App\Services\StripePaymentGateway;
use Illuminate\Support\ServiceProvider;

class PaymentServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(PaymentGateway::class, StripePaymentGateway::class);
    }

    public function boot(): void
    {
        // Safe to use ANY service here, since every provider's register()
        // has already finished running by this point.
    }
}

From this point on, any class anywhere in the application that type-hints PaymentGateway in its constructor automatically receives a StripePaymentGateway instance — the controller, job, or listener using it never has to know, or care, which concrete class is actually behind the interface.

Laravel's Own Core Features Are Just Providers

This same pattern is exactly how Laravel's own built-in features work. Auth, Cache, Queue, the routing system, the validation system — every one of these is bootstrapped by a bundled service provider, registered in the framework's own provider list long before your application's providers run. This is precisely why Laravel feels so modular and swappable: because even its "core" functionality goes through the exact same registration mechanism available to you, an alternative implementation of any of these systems could, in principle, be swapped in by registering a different provider.

Where this leads: With providers and the container in place, you have everything needed to understand how Laravel wires up a full feature — starting with one of its biggest: logging users in and out, covered next in Authentication.