Skip to main content

Command

php artisan make:provider {name} --module={module}
Create a new service provider class in your module’s src/Providers directory.

Parameters

name
string
required
The name of the provider classConventions:
  • Use PascalCase
  • End with “ServiceProvider” or “Provider”
Examples:
  • BlogServiceProvider
  • RepositoryServiceProvider
  • EventServiceProvider

Options

--module
string
required
The name of the module where the provider should be createdExample: --module=blog

Examples

Basic Service Provider

php artisan make:provider BlogServiceProvider --module=blog
Generates a service provider:
namespace Modules\Blog\Providers;

use Illuminate\Support\ServiceProvider;

class BlogServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap services.
     */
    public function boot(): void
    {
        //
    }
}
Location: app-modules/blog/src/Providers/BlogServiceProvider.php

Repository Service Provider

php artisan make:provider RepositoryServiceProvider --module=blog
Customize it to bind interfaces to implementations:
namespace Modules\Blog\Providers;

use Illuminate\Support\ServiceProvider;
use Modules\Blog\Contracts\PostRepositoryInterface;
use Modules\Blog\Repositories\PostRepository;

class RepositoryServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(
            PostRepositoryInterface::class,
            PostRepository::class
        );
    }
}

Route Service Provider

php artisan make:provider RouteServiceProvider --module=blog
Customize it to load module routes:
namespace Modules\Blog\Providers;

use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;

class RouteServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $this->routes(function () {
            Route::middleware('web')
                ->group(__DIR__.'/../../routes/web.php');

            Route::middleware('api')
                ->prefix('api')
                ->group(__DIR__.'/../../routes/api.php');
        });
    }
}

Event Service Provider

php artisan make:provider EventServiceProvider --module=blog
Customize it to register event listeners:
namespace Modules\Blog\Providers;

use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Modules\Blog\Events\PostPublished;
use Modules\Blog\Listeners\SendPostNotification;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        PostPublished::class => [
            SendPostNotification::class,
        ],
    ];

    public function boot(): void
    {
        //
    }
}

Module-Specific Behavior

Simple Implementation

The MakeProvider command uses the ModularizeGeneratorCommand trait without any custom overrides:
MakeProvider.php:1-12
namespace InterNACHI\Modular\Console\Commands\Make;

use Illuminate\Foundation\Console\ProviderMakeCommand;
use InterNACHI\Modularize\ModularizeGeneratorCommand;

class MakeProvider extends ProviderMakeCommand
{
    use ModularizeGeneratorCommand;
}
This means the command:
  1. Uses Laravel’s standard provider generation
  2. Adjusts the namespace to your module
  3. Places the file in your module’s src/Providers directory
Service providers follow the standard Laravel implementation with only namespace and path adjustments for modules.

Common Provider Patterns

Binding Interfaces

Register service container bindings:
public function register(): void
{
    $this->app->singleton(CacheInterface::class, RedisCache::class);
    
    $this->app->bind(PaymentGateway::class, function ($app) {
        return new StripeGateway(
            config('services.stripe.key')
        );
    });
}

Loading Configuration

Publish and merge module configuration:
public function register(): void
{
    $this->mergeConfigFrom(
        __DIR__.'/../../config/blog.php',
        'blog'
    );
}

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

Loading Views

Register view namespaces:
public function boot(): void
{
    $this->loadViewsFrom(
        __DIR__.'/../../resources/views',
        'blog'
    );
    
    $this->publishes([
        __DIR__.'/../../resources/views' => resource_path('views/vendor/blog'),
    ], 'blog-views');
}

Loading Translations

Register translation files:
public function boot(): void
{
    $this->loadTranslationsFrom(
        __DIR__.'/../../resources/lang',
        'blog'
    );
    
    $this->publishes([
        __DIR__.'/../../resources/lang' => lang_path('vendor/blog'),
    ], 'blog-translations');
}

Loading Migrations

Register module migrations:
public function boot(): void
{
    $this->loadMigrationsFrom(
        __DIR__.'/../../database/migrations'
    );
}

Registering Commands

Register Artisan commands:
public function boot(): void
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            \Modules\Blog\Console\Commands\PublishPost::class,
            \Modules\Blog\Console\Commands\ImportPosts::class,
        ]);
    }
}

Registering Policies

Register authorization policies:
use Illuminate\Support\Facades\Gate;
use Modules\Blog\Models\Post;
use Modules\Blog\Policies\PostPolicy;

public function boot(): void
{
    Gate::policy(Post::class, PostPolicy::class);
}

Registering Middleware

Register route middleware:
use Illuminate\Routing\Router;
use Modules\Blog\Http\Middleware\CheckPostOwnership;

public function boot(): void
{
    $router = $this->app->make(Router::class);
    $router->aliasMiddleware('post.owner', CheckPostOwnership::class);
}

Registering Your Provider

Automatic Discovery

Laravel automatically discovers service providers in modules through package discovery. Add to your module’s composer.json:
composer.json
{
    "extra": {
        "laravel": {
            "providers": [
                "Modules\\Blog\\Providers\\BlogServiceProvider"
            ]
        }
    }
}

Manual Registration

Alternatively, register in config/app.php:
config/app.php
'providers' => [
    // Other providers...
    
    Modules\Blog\Providers\BlogServiceProvider::class,
],
Use package discovery (composer.json) for better module portability.

Service Provider Lifecycle

Registration Phase

The register() method is called first for all providers:
public function register(): void
{
    // Bind services to the container
    // Register singletons
    // Merge configuration
}
Only bind services in register(). Don’t access any services here as they may not be available yet.

Boot Phase

The boot() method is called after all providers are registered:
public function boot(): void
{
    // Load routes, views, migrations
    // Publish assets
    // Register commands
    // Use other services
}

Deferred Providers

Defer loading until services are needed:
use Illuminate\Contracts\Support\DeferrableProvider;

class RepositoryServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->app->singleton(PostRepository::class);
    }

    public function provides(): array
    {
        return [PostRepository::class];
    }
}

Best Practices

Create multiple focused providers instead of one large provider:
  • RepositoryServiceProvider - Repository bindings
  • EventServiceProvider - Event listeners
  • RouteServiceProvider - Route loading
  • ViewServiceProvider - View composers and components
Only bind services to the container in register():
// Good
public function register(): void
{
    $this->app->singleton(MyService::class);
}

// Bad - don't use other services here
public function register(): void
{
    $service = $this->app->make(OtherService::class);
}
Implement DeferrableProvider for services that aren’t always needed:
class RepositoryServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function provides(): array
    {
        return [PostRepository::class];
    }
}
Add comments documenting what can be published:
public function boot(): void
{
    // Publish with: php artisan vendor:publish --tag=blog-config
    $this->publishes([
        __DIR__.'/../../config/blog.php' => config_path('blog.php'),
    ], 'blog-config');
}

Testing Service Providers

Test that your provider correctly registers services:
namespace Modules\Blog\Tests;

use Modules\Blog\Contracts\PostRepositoryInterface;
use Modules\Blog\Repositories\PostRepository;
use Tests\TestCase;

class RepositoryServiceProviderTest extends TestCase
{
    public function test_it_binds_post_repository(): void
    {
        $repository = $this->app->make(PostRepositoryInterface::class);
        
        $this->assertInstanceOf(PostRepository::class, $repository);
    }
}

See Also

Build docs developers (and LLMs) love