Back to posts
Laravel

Laravel Service Providers: What You Need to Know

Learn how Laravel Service Providers work, from the register() and boot() methods to deferred providers and conditional registration.

June 13, 20253 min read

Service Providers are the foundation of Laravel's bootstrapping process. They're the glue between Laravel's internal services and your application logic - and once you understand them, you unlock a much deeper level of control over your application.

What Do Service Providers Do?

Every major feature in Laravel is bootstrapped through a service provider:

  • Registering bindings in the IoC container
  • Binding interfaces to concrete implementations
  • Loading routes, config files, views, and migrations
  • Hooking into application lifecycle events

The Core Structure: register() and boot()

Every service provider extends Illuminate\Support\ServiceProvider and has two key methods.

register()

This runs before the application fully boots. Use it only to bind things into the service container - never try to use other services here since they may not be registered yet.

php
public function register(): void
{
    $this->app->singleton(PaymentGatewayInterface::class, StripeGateway::class);
 
    $this->mergeConfigFrom(__DIR__.'/../config/payments.php', 'payments');
}

boot()

This runs after all providers have been registered. This is where you can safely use services registered by other providers.

php
public function boot(): void
{
    $this->loadRoutesFrom(__DIR__.'/../routes/api.php');
 
    $this->publishes([
        __DIR__.'/../config/payments.php' => config_path('payments.php'),
    ]);
}

Deferred Service Providers

If your provider only registers container bindings (not routes, events, etc.), you can make it deferred - it won't load on every request, only when the binding is actually needed.

php
use Illuminate\Contracts\Support\DeferrableProvider;
 
class ReportServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->app->singleton(ReportGenerator::class, PdfReportGenerator::class);
    }
 
    public function provides(): array
    {
        return [ReportGenerator::class];
    }
}

This is a subtle but important performance optimization - especially for larger applications with many providers.

The Provider Lifecycle

When Laravel boots, it calls registerConfiguredProviders() which reads from:

  • config/app.php (Laravel ≤ 10)
  • bootstrap/providers.php (Laravel 11+)

The process:

  1. Each provider's register() method is called
  2. All registered providers are stored internally
  3. Each provider's boot() method is called

Creating Your Own Provider

bash
php artisan make:provider PaymentServiceProvider

Then register it in bootstrap/providers.php:

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

Conditional Registration

You can register providers conditionally based on environment, which is useful for dev-only tooling:

php
public function register(): void
{
    if ($this->app->environment('local', 'testing')) {
        $this->app->register(DebugToolsProvider::class);
    }
}

This keeps your production app lean - no debug panels or test helpers leaking into prod.

When to Create a Custom Provider

Create one when you:

  • Build a reusable package that needs to integrate with Laravel's container
  • Have a set of related bindings and configuration that belong together
  • Need to hook into the application lifecycle in a clean, organized way

Conclusion

Mastering Service Providers gives you complete control over your application's structure and lifecycle. Once you understand the register/boot split and when to defer, you can build cleaner, more extensible Laravel applications - whether you're building a monolith or a suite of internal packages.