nWidart/laravel-modules: Module Management for Large Laravel Apps
Module Management In Laravel
At a glance
- What is it?
- A Composer package that gives a Laravel application an artisan-driven module layer, with its own service providers, routes, views and migrations. The useful part is the scaffolding and lifecycle; the trade-off is a second autoloading system bolted onto Composer.
- Who is it for?
- Adopt nWidart/laravel-modules when a Laravel app has grown past what folders under app/ can organise, and when you want module boundaries enforced by artisan commands rather than convention. Do not adopt it for a small application, and do not adopt it expecting modules to be installable packages: the README treats a module as a Laravel package in shape, but the autoloading still runs through your application's composer.json.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 170 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem: Laravel's default layout stops scaling before the code does
A stock Laravel application puts controllers in app/Http/Controllers, models in app/Models, and views in resources/views. That is fine until the application has several distinct domains, at which point a single controller directory holds unrelated concerns and a change to one domain touches files scattered across five top-level folders. Laravel ships no first-party answer to this. The framework gives you service providers and packages, but packaging a domain as a Composer package means a separate repository, a separate version, and a release cycle you did not ask for.
nWidart/laravel-modules fills that gap. The README describes it as a package created to manage a large Laravel app using modules, and defines a module as something like a Laravel package: it has its own views, controllers and models. The intended user is a team maintaining one application whose domains are stable enough to name, and who want those names to appear in the filesystem and in artisan output rather than only in a wiki page.
The project is a re-published and reorganised version of pingpong/modules, which the README says is no longer maintained. It adds tests, which the original did not have. That lineage matters when you read older tutorials: the pingpong commands and the nwidart commands are not the same, and search results still mix them.
How a module is structured and loaded
A module is a directory with a composer.json, and the package's configuration file controls where those directories live. By default they sit in a Modules/ folder at the application root. Each module carries its own service provider, which Laravel boots like any other provider, so routes, views, migrations and translations inside the module are registered through the normal framework mechanisms rather than a parallel one.
The unusual part is autoloading. Module classes are not loaded automatically. The README states that from v11.0 the old "Modules\\": "modules/" entry is no longer required and should be removed from composer.json if present. In its place you add the wikimedia/composer-merge-plugin to the extra section and point it at Modules/*/composer.json. Composer then reads each module's own composer.json and merges its autoload rules into the root autoloader.
That design has a consequence worth naming. Module dependencies are declared in the module's composer.json, but resolution happens through the application's Composer run, so a module cannot be installed independently of the application the way a real package can. The boundary is organisational, not a distribution boundary. If you want modules that other projects can pull in, this is the wrong tool and a private Composer repository is the right one.
Installing it and scaffolding a first module
Installation is a single Composer command. The package registers its service provider and alias automatically, so no manual provider entry is needed in config/app.php.
composer require nwidart/laravel-modulesPublishing the configuration file is optional and copies it into your application's config directory, where you can change the module path and other defaults.
php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider"The autoloading step is where first-time installs go wrong. Composer asks whether you trust the merge plugin, and answering n leaves modules unloaded. The README's own prompt looks like this:
Do you trust "wikimedia/composer-merge-plugin" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?]Answer y, or add the entry by hand. The README notes that if the plugin is set to false, modules will not be autoloaded.
"config": {
"allow-plugins": {
"wikimedia/composer-merge-plugin": true
}
}Then add the merge plugin to the extra section so Composer picks up each module's composer.json:
"extra": {
"merge-plugin": {
"include": [
"Modules/*/composer.json"
]
}
}After editing composer.json, run composer dump-autoload. The README calls this out as a tip, and skipping it is the most common reason a freshly scaffolded module is not found. The module creation command itself is not documented in the README; the documentation site at laravelmodules.com is where the README points for the full command list, so treat that site as the source for the exact artisan command names and their options.
The merge plugin is the real dependency, and it is easy to misconfigure
The single most likely failure mode is not in the package at all. It is the interaction between Composer's plugin permission system and the merge plugin. Composer blocks plugins from executing code until they are allowed, and the merge plugin needs that permission to read Modules/*/composer.json. If the permission is missing or set to false, the package installs cleanly, artisan commands may still run, and the module classes simply do not resolve. The error you see is a class-not-found from deep inside the framework, which points nowhere near the actual cause.
A second constraint: every module needs a valid composer.json for the merge to work. A hand-created module directory without one is invisible to the autoloader. Teams that copy a module folder as a starting template and forget to rename the namespace inside its composer.json get collisions rather than errors.
The README does not document rollback or removal of a module, and it does not describe what happens to a module's migrations once the module directory is deleted. Those are things to determine from the documentation site or from the source before you commit to the structure. The configuration file is the place to look if you need modules somewhere other than Modules/, but the README does not enumerate its keys.
Where it sits next to plain Laravel packages and DDD layering
The honest alternative is not another module package. It is Laravel's own package development, or simply domain folders under app/ with a service provider per domain. A first-party package gives you a real distribution boundary: version constraints, a separate test suite, and installation into other applications. Domain folders cost nothing and require no merge plugin. What neither gives you is scaffolding. laravel-modules' value is concentrated in the commands that generate a module's skeleton and in the fact that the whole team shares one convention for where domain code lives.
A second comparison is domain-driven design layering, which search data suggests people ask about alongside this package. DDD organises code by layer (domain, application, infrastructure) and is orthogonal to this package, which organises by feature. You can use both, but they pull in different directions: a DDD layout puts all repositories together, while a module layout puts one feature's repository next to its controllers. Pick one as the primary axis, because mixing them produces a tree nobody can predict.
On ecosystem integrations, the README says nothing about Livewire, Inertia or Filament. Those combinations are documented by third parties, not by this project, so verify compatibility against the specific package versions you use rather than assuming the module layer handles it.
Maintenance, versions and what the MIT licence means here
The repository is not archived, and the last push was on 2026-04-13. The most recent release is v13.0.0 from 2026-03-19, with v12.0.5 released the same day and v12.0.4 before that in 2025. The README's compatibility table maps Laravel 13.0 to ^13.0 and Laravel 12.0 to ^12.0, so the major version tracks the Laravel major. That is the upgrade cost in practice: a Laravel major upgrade is also a laravel-modules major upgrade, and the two should be planned together rather than sequentially.
The README states the package is supported and tested in Laravel 11, while the table lists versions up to 13. The table is the more current signal for which constraint to require, but the mismatch is worth noting if you are on 12 or 13 and want reassurance from the README alone.
The licence is MIT. That permits commercial use and modification, with the usual requirement to keep the copyright and permission notice. It is a permissive licence, not a copyleft one, so it does not impose obligations on your application's own source. This is a description of the licence text, not legal advice; read LICENSE.md for the actual terms.
Editorial conclusion
Adopt nWidart/laravel-modules when a Laravel app has grown past what folders under app/ can organise, and when you want module boundaries enforced by artisan commands rather than convention. Do not adopt it for a small application, and do not adopt it expecting modules to be installable packages: the README treats a module as a Laravel package in shape, but the autoloading still runs through your application's composer.json. Before committing, verify two things in a scratch project: that wikimedia/composer-merge-plugin is allowed in config.allow-plugins, and that Modules/*/composer.json is actually merged after composer dump-autoload.
Frequently asked questions
What is nWidart/laravel-modules used for?
It manages a large Laravel application by splitting it into modules. The README defines a module as being like a Laravel package, with its own views, controllers and models.
Why are my nWidart/laravel-modules classes not autoloading?
The README states that if wikimedia/composer-merge-plugin is set to false, modules will not be autoloaded. The plugin must be allowed in config.allow-plugins and listed in the extra section, then you run composer dump-autoload.
Which Laravel version does nWidart/laravel-modules support?
The README's compatibility table maps each Laravel major to a matching package major, from Laravel 5.4 with ^1.0 through Laravel 13.0 with ^13.0. The README also states the package is supported and tested in Laravel 11.
Does nWidart/laravel-modules require the Modules\\ namespace in composer.json?
No. The README states that from v11.0 autoloading "Modules\\": "modules/" is no longer required and should be removed from composer.json if present.
Is nWidart/laravel-modules the same as pingpong/modules?
It is a re-published, reorganised and maintained version of pingpong/modules, which the README says is no longer maintained. The README notes the maintained version adds tests, which the original did not have.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nwidart-laravel-modules)