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.
| Method | Purpose | Important rule |
|---|---|---|
register() | ONLY for binding things into the service container | Must 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 else | Runs after every provider's register() has already executed, so it's always safe to use any service here |
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.