Package service providers — building installable Laravel packages
Advanced5 min read·lv-03-004
laravel-src
Concept
Building installable Laravel packages requires a service provider that handles publishing, registering, and loading the package's resources in a host application. The package's service provider is the API surface — it's how the package integrates with Laravel.
Key service provider package methods:
$this->loadRoutesFrom(string $path): Register routes from a file.$this->loadMigrationsFrom(string $path): Register migration path (auto-discovered byartisan migrate).$this->loadViewsFrom(string $path, string $namespace): Register a view namespace ($namespace::view.name).$this->loadTranslationsFrom(string $path, string $namespace): Register a translation namespace.$this->mergeConfigFrom(string $path, string $key): Merge package config with app config. User's app config takes precedence.$this->publishes(array $paths, string|array $groups): Register publishable files/dirs. Users runphp artisan vendor:publish --tag=group-name.
Package auto-discovery: Add to composer.json:
json
"extra": {
"laravel": {
"providers": ["Vendor\\Package\\PackageServiceProvider"],
"aliases": {"Package": "Vendor\\Package\\Facades\\Package"}
}
}Laravel 5.5+ reads this and auto-registers the provider without requiring the user to edit config/app.php.
Stub-based config publishing: Always provide a publishable config with sensible defaults. Use mergeConfigFrom so the package works without publishing. Publishing lets users customize.
Code Example
php
<?php
namespace Vendor\Analytics;
use Illuminate\Support\ServiceProvider;
class AnalyticsServiceProvider extends ServiceProvider
{
public function register(): void
{
// Merge package defaults with user's published config
// User's config takes precedence for matching keys
$this->mergeConfigFrom(
__DIR__ . '/../config/analytics.php',
'analytics'
);
$this->app->singleton(\Vendor\Analytics\Analytics::class, function($app) {
return new Analytics(config('analytics'));
});
}
public function boot(): void
{
// Load package routes
$this->loadRoutesFrom(__DIR__ . '/../routes/web.php');
// Load package views under 'analytics' namespace
// Usage in templates: @include('analytics::dashboard')
$this->loadViewsFrom(__DIR__ . '/../resources/views', 'analytics');
// Load package migrations
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
// Register publishable assets
$this->publishes([
__DIR__ . '/../config/analytics.php' => config_path('analytics.php'),
], 'analytics-config');
$this->publishes([
__DIR__ . '/../resources/views' => resource_path('views/vendor/analytics'),
], 'analytics-views');
$this->publishes([
__DIR__ . '/../database/migrations' => database_path('migrations'),
], 'analytics-migrations');
// Combine all publishable under one tag
$this->publishes([
__DIR__ . '/../config/analytics.php' => config_path('analytics.php'),
__DIR__ . '/../database/migrations' => database_path('migrations'),
], 'analytics');
}
public function provides(): array
{
return [Analytics::class];
}
}bash
# Users publish the config
php artisan vendor:publish --tag=analytics-config
# Or publish everything under 'analytics' tag
php artisan vendor:publish --provider="Vendor\Analytics\AnalyticsServiceProvider"