waventra / laravel-modules
Laravel modules package: independent modules outside app/ with repository pattern, service layer, and artisan module:make generators for Laravel 11 and 12.
Requires
- php: ^8.2
- illuminate/console: ^11.0|^12.0
- illuminate/database: ^11.0|^12.0
- illuminate/filesystem: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0
- phpunit/phpunit: ^11.0
README
Laravel modules package for PHP 8.2+ and Laravel 11/12. Split an application into independent modules outside app/, each with HTTP, database, models, repository, and service layers.
Install: composer require waventra/laravel-modules
Source: github.com/waventra/laravel-modules
Installation
composer require waventra/laravel-modules
The service provider and Module facade are auto-discovered.
php artisan vendor:publish --tag=modules-config php artisan vendor:publish --tag=modules-stubs
| Tag | Destination |
|---|---|
modules-config |
config/modules.php |
modules-stubs |
stubs/modules/ |
Enabled/disabled state is stored in modules_statuses.json at the project root.
Artisan commands
| Command | Description |
|---|---|
module:make {name} |
Create a module under Modules/{Name} with providers, routes, and (unless --plain) model, repository, service, controller, form requests, and a migration. |
module:make {name} --plain |
Same as above but skeleton only: folders, providers, routes, and config. No domain classes. |
module:list |
List every module with alias, enabled/disabled status, priority, and path. |
module:enable {name} |
Enable a module so its providers, routes, and migrations load. Writes modules_statuses.json. |
module:disable {name} |
Disable a module. It stays on disk but is not registered. |
module:make-model {name} {module} |
Create an Eloquent model in Models/. Add --migration to also create a table migration. |
module:make-repository {name} {module} |
Create {Name}RepositoryInterface under Repositories/Contracts/ and {Name}Repository under Repositories/. Bind them in RepositoryServiceProvider. |
module:make-service {name} {module} |
Create a service class in Services/ that extends BaseService and takes the repository interface. |
module:make-controller {name} {module} |
Create a resource controller in Http/Controllers/ wired to the service. Use --plain for an empty controller. |
module:make-request {name} {module} |
Create a form request in Http/Requests/. |
module:make-migration {name} {module} |
Create a migration in Database/Migrations/. Names like create_{table}_table generate a create-table migration. |
API routes registered by a full module use the api middleware group and Route::apiResource.
Folder structure
Modules live in Modules/ at the project root, not inside app/. module:make {name} creates:
Modules/{Name}/
├── Http/
│ ├── Controllers/
│ ├── Requests/
│ ├── Resources/ # API JsonResource classes
│ └── Middleware/
├── Database/
│ ├── Migrations/
│ ├── Seeders/
│ └── Factories/
├── Models/
├── Repositories/
│ └── Contracts/
├── Services/
├── Routes/
│ ├── api.php
│ └── web.php
├── Providers/
├── Resources/
│ ├── views/ # Blade views
│ ├── css/
│ └── js/
├── lang/
├── Config/
├── Tests/
├── module.json
└── composer.json
Request flow: Controller → Service → Repository → Model.
Bind repositories in the module RepositoryServiceProvider:
$this->app->bind({Name}RepositoryInterface::class, {Name}Repository::class);
Facade and helpers
use Waventra\Modules\Facades\Module; Module::all(); Module::allEnabled(); Module::has('{name}'); Module::find('{name}'); Module::findOrFail('{name}'); Module::enable('{name}'); Module::disable('{name}');
module(); module('{name}'); module_path('{name}'); module_path('{name}', 'Routes/api.php'); module_namespace('{name}'); modules_path();
Configuration
File: config/modules.php.
| Key | Default | Purpose |
|---|---|---|
namespace |
Modules |
PSR-4 prefix |
paths.modules |
base_path('Modules') |
Module root |
paths.statuses |
base_path('modules_statuses.json') |
Enable/disable map |
generator.* |
see config | Folders created by module:make |
module.json fields: name, alias, description, priority, providers. Lower priority loads earlier.
The module service provider loads:
- Migrations:
Database/Migrations - Views:
Resources/views - Translations:
lang - Config:
Config/config.php
Autoloading
Namespace maps 1:1 to folders under Modules/{Name}/. No composer dump-autoload is required after module:make.
Discover module tests in the host app:
<testsuite name="Modules"> <directory suffix="Test.php">Modules/*/Tests</directory> </testsuite>
Custom stubs
php artisan vendor:publish --tag=modules-stubs
Files in stubs/modules/ override package stubs and control generated code.
Path repository (local package)
{
"repositories": [
{
"type": "path",
"url": "../laravel-modules"
}
]
}
composer require waventra/laravel-modules:@dev
Copyright and license
Copyright (c) 2026 Waventra. All rights reserved.
This software is free to use. You may not copy, modify, or sell it.
See LICENSE for the full terms.