nwidart/laravel-modules
Modularize large Laravel apps with nwidart/laravel-modules. Create self-contained modules (controllers, models, views, routes, config) with Artisan generators, module discovery, enabling/disabling, and per-module resources—tested and maintained across modern Laravel versions.
Installation
composer require nwidart/laravel-modules
The package auto-registers its service provider and aliases.
Publish Configuration (Optional)
php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider"
Enable Composer Merge Plugin
Add to composer.json:
"extra": {
"merge-plugin": {
"include": ["Modules/*/composer.json"]
}
},
"config": {
"allow-plugins": {
"wikimedia/composer-merge-plugin": true
}
}
Run:
composer dump-autoload
Create Your First Module
php artisan module:make Blog
This generates a module skeleton in Modules/Blog/ with:
ModuleServiceProviderroutes/web.php/routes/api.phpHttp/Controllers/ (empty by default)Database/Migrations/Resources/views/Enable the Module
php artisan module:enable Blog
php artisan module:make-controller Blog Post --web
This creates Modules/Blog/Http/Controllers/PostController.php with a web route stub.
php artisan module:make <ModuleName>
php artisan module:make-model Blog Post
php artisan module:make-controller Blog Post --web
php artisan module:make-migration Blog create_posts_table
php artisan module:seed Blog --class=PostTableSeeder
php artisan module:enable/disable <ModuleName>
RouteServiceProvider (generated in Modules/<Module>/Routes/).php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider" --tag="stubs"
vite.config.js or webpack.mix.js in the module root.import './Resources/assets/js/app.js';
npm run dev --prefix Modules/<Module>
ModuleServiceProvider automatically.register()/boot() methods.php artisan module:migrate Blog
php artisan module:migrate:rollback Blog
Modules/<Module>/ with namespace Modules\<Module>.config/modules.php:
'namespace' => 'App\\Modules',
'path' => 'app/Modules',
--module flag in tests:
$this->artisan('module:enable', ['module' => 'Blog'])->assertExitCode(0);
EventServiceProvider by default (v11+).event(new PostCreated($post));
php artisan module:make-controller Blog Post --api
web middleware group.php artisan module:make-component Blog Alert
view()->addNamespace().php artisan module:seed Blog --class=PostTableSeeder
--force to overwrite existing data.Class not found errors for module classes.composer dump-autoload is run after adding modules.merge-plugin is enabled in composer.json.Modules\Blog vs Modules\blog).Route::prefix('blog')->group(function () { ... });
php artisan module:disable UnusedModule
Table already exists errors.--force for migrations:
php artisan module:migrate Blog --force
vite.config.js or webpack.mix.js exists in the module root.@vite(['resources/css/app.css', 'Modules/Blog/Resources/css/blog.css'])
php artisan optimize:clear
php artisan module:v6:migrate
config/modules.php:
'activator' => \Nwidart\Modules\Activators\DatabaseActivator::class,
php artisan module:list
config/app.php for:
'providers' => [
// ...
Nwidart\Modules\ModulesServiceProvider::class,
],
Route::get('/debug/routes', function () {
return collect(Route::getRoutes()->getByName())->count();
});
npm run dev --prefix Modules/Blog -- --debug
config/modules.php:
'log' => true,
storage/logs/laravel.log for module-related entries.php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider" --tag="stubs"
Modules/<Module>/stubs/.class CacheActivator implements ActivatorContract {
public function isEnabled(string $module): bool { ... }
public function enable(string $module): void { ... }
public function disable(string $module): void { ... }
}
config/modules.php:
'activator' => App\Modules\CacheActivator::class,
if (auth()->user()->isAdmin()) {
Module::enable('AdminPanel');
}
config() with module-specific keys:
config(['modules.blog.enabled' => true]);
php artisan vendor:publish --tag=blog-config
$this->partialMock(Module::class, 'isEnabled')
->shouldReturn(true);
--module flag for module-specific tests:
php artisan test --module=Blog
How can I help you explore Laravel packages today?