Service Providers
Service Providers
Service Providers are the central place of all Laravel application bootstrapping. They are responsible for binding services into the container, registering event listeners, middleware, routes, and other setup tasks. Understanding service providers is key to understanding how Laravel applications are configured and bootstrapped.
What are Service Providers?
Service Providers are classes that register and bootstrap components of your Laravel application. Every Laravel application has at least one service provider (AppServiceProvider), and the framework itself includes many providers for core services.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// Bind services into the container
// This runs BEFORE any boot() method
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
// Perform post-registration bootstrapping
// This runs AFTER all providers have registered
}
}
register() method should only bind things into the service container. The boot() method is called after all providers have been registered, so you can safely use other services in boot().
The Register Method
The register method is where you bind services, interfaces, and other dependencies into the service container:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\PaymentGateway;
use App\Services\StripePaymentGateway;
use App\Contracts\ReportGeneratorInterface;
use App\Services\PdfReportGenerator;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
// Simple binding
$this->app->bind(PaymentGateway::class, function ($app) {
return new StripePaymentGateway(
config('services.stripe.key')
);
});
// Singleton binding
$this->app->singleton(
ReportGeneratorInterface::class,
PdfReportGenerator::class
);
// Register config file
$this->mergeConfigFrom(
__DIR__.'/../config/mypackage.php',
'mypackage'
);
// Conditional registration based on environment
if ($this->app->environment('local')) {
$this->app->register(DebugServiceProvider::class);
}
}
}
The Boot Method
The boot method runs after all service providers have been registered, making it safe to use other services:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Blade;
use App\Models\User;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
// Share data with all views
View::share('appName', config('app.name'));
// Define authorization gates
Gate::define('update-post', function (User $user, $post) {
return $user->id === $post->user_id;
});
// Register Blade directives
Blade::directive('datetime', function ($expression) {
return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
});
// Register model observers
User::observe(UserObserver::class);
// Publish package assets
$this->publishes([
__DIR__.'/../resources/views' => resource_path('views/vendor/mypackage'),
], 'mypackage-views');
// Register macros
\Illuminate\Support\Str::macro('titleSnake', function ($value) {
return \Illuminate\Support\Str::title(
str_replace('_', ' ', $value)
);
});
}
}
Dependency Injection in Boot Method
You can type-hint dependencies in the boot method, and the container will automatically inject them:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Contracts\View\Factory as ViewFactory;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
//
}
/**
* Dependencies automatically injected
*/
public function boot(
ResponseFactory $response,
ViewFactory $view
): void {
// Use injected dependencies
$view->composer('*', function ($view) {
$view->with('currentYear', date('Y'));
});
// Add custom response macro
$response->macro('caps', function ($value) use ($response) {
return $response->make(strtoupper($value));
});
}
}
Creating Custom Service Providers
When building larger applications, it's good practice to create dedicated service providers for different components:
// Generate a new service provider
php artisan make:provider PaymentServiceProvider
// app/Providers/PaymentServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\Payment\StripeGateway;
use App\Services\Payment\PayPalGateway;
use App\Contracts\PaymentGatewayInterface;
class PaymentServiceProvider extends ServiceProvider
{
public function register(): void
{
// Bind payment gateway based on config
$this->app->singleton(
PaymentGatewayInterface::class,
function ($app) {
$driver = config('payment.default');
return match($driver) {
'stripe' => new StripeGateway(
config('payment.stripe.key')
),
'paypal' => new PayPalGateway(
config('payment.paypal.client_id')
),
default => throw new \Exception("Unsupported payment driver: {$driver}")
};
}
);
}
public function boot(): void
{
// Publish configuration
$this->publishes([
__DIR__.'/../config/payment.php' => config_path('payment.php'),
], 'payment-config');
}
}
// Register in config/app.php providers array
'providers' => [
// ... other providers
App\Providers\PaymentServiceProvider::class,
],
Deferred Providers
Deferred providers only load when their services are actually needed, improving application performance:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;
use App\Services\ReportGenerator;
class ReportServiceProvider extends ServiceProvider implements DeferrableProvider
{
public function register(): void
{
$this->app->singleton(ReportGenerator::class, function ($app) {
return new ReportGenerator(
$app->make('db'),
$app->make('config')
);
});
}
/**
* Get the services provided by the provider.
*
* @return array<int, string>
*/
public function provides(): array
{
// List all services this provider offers
return [
ReportGenerator::class,
];
}
}
// Benefits:
// - Provider only loads when ReportGenerator is needed
// - Reduces bootstrap time
// - Improves performance for requests that don't need reports
Publishing Package Assets
Service providers allow packages to publish configuration files, views, migrations, and other assets:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class MyPackageServiceProvider extends ServiceProvider
{
public function boot(): void
{
// Publish configuration
$this->publishes([
__DIR__.'/../config/mypackage.php' => config_path('mypackage.php'),
], 'mypackage-config');
// Publish views
$this->publishes([
__DIR__.'/../resources/views' => resource_path('views/vendor/mypackage'),
], 'mypackage-views');
// Publish migrations
$this->publishes([
__DIR__.'/../database/migrations' => database_path('migrations'),
], 'mypackage-migrations');
// Publish assets (CSS, JS, images)
$this->publishes([
__DIR__.'/../public' => public_path('vendor/mypackage'),
], 'mypackage-assets');
// Publish multiple asset groups at once
$this->publishes([
__DIR__.'/../config/mypackage.php' => config_path('mypackage.php'),
__DIR__.'/../resources/views' => resource_path('views/vendor/mypackage'),
], 'mypackage-all');
}
}
// Users publish with artisan commands:
php artisan vendor:publish --tag=mypackage-config
php artisan vendor:publish --tag=mypackage-views
php artisan vendor:publish --tag=mypackage-all
php artisan vendor:publish --provider="App\Providers\MyPackageServiceProvider"
Loading Package Resources
Service providers can load views, translations, migrations, and routes from packages:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class MyPackageServiceProvider extends ServiceProvider
{
public function boot(): void
{
// Load package views
$this->loadViewsFrom(__DIR__.'/../resources/views', 'mypackage');
// Load package translations
$this->loadTranslationsFrom(__DIR__.'/../lang', 'mypackage');
// Load package migrations
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
// Load package routes
$this->loadRoutesFrom(__DIR__.'/../routes/web.php');
}
}
// Using loaded resources:
// Views: return view('mypackage::dashboard');
// Translations: __('mypackage::messages.welcome')
// Migrations: run automatically with php artisan migrate
// Routes: automatically registered
Summary
Service Providers are the cornerstone of Laravel application configuration:
- Register Method: Bind services into the container only
- Boot Method: Bootstrap services, views, gates, etc. after registration
- Dependency Injection: Boot method can type-hint dependencies
- Custom Providers: Organize application by creating dedicated providers
- Deferred Providers: Load only when needed for better performance
- Publishing: Allow users to customize package assets
- Loading Resources: Make package views, translations, and routes available
In the next lesson, we'll explore Artisan Console Commands and how to create custom CLI tools for your Laravel application.