Skip to main content

Overview

Laravel Modular provides a lighter-weight alternative to nwidart/laravel-modules that follows Laravel conventions more closely. This guide will help you understand the differences and migrate your existing modules.

Key Differences

Philosophy

Laravel Modular is designed with different goals in mind:
Laravel Modular focuses on organization rather than dynamic module management. If you need to dynamically enable/disable modules at runtime (common in CMS applications), nwidart/laravel-modules may be a better fit.
Aspectnwidart/laravel-modulesLaravel Modular
Directory StructureCustom module structureStandard Laravel conventions
AutoloadingCustom autoloaderComposer path repositories
DiscoveryCustom discovery systemLaravel package discovery
Dynamic LoadingEnable/disable modules at runtimeAll modules always loaded
WeightFull-featured CMS solutionMinimal organizational tooling

Technical Approach

nwidart/laravel-modules uses its own directory structure and conventions, making it powerful but requiring a learning curve beyond Laravel itself. Laravel Modular leverages:

Migration Steps

1

Install Laravel Modular

Install the package via Composer:
composer require internachi/modular
Laravel will auto-discover the package automatically.
2

Publish and Configure

Publish the configuration file:
php artisan vendor:publish --tag=modular-config
Edit config/app-modules.php to set your namespace:
'modules_namespace' => 'YourOrg', // Recommended over 'Modules'
'modules_directory' => 'app-modules',
3

Restructure Module Directories

Laravel Modular uses Laravel package conventions. You’ll need to restructure your modules:Before (nwidart structure):
Modules/
  Blog/
    Config/
    Console/
    Database/
    Entities/      ← Models
    Http/
    Providers/
    Resources/
    Routes/
    Tests/
    module.json    ← Module metadata
After (Laravel Modular structure):
app-modules/
  blog/
    composer.json  ← Package metadata
    src/           ← Models, Controllers, etc.
    routes/
    resources/
    database/
    tests/
4

Update Directory Mappings

Map your nwidart directories to Laravel Modular conventions:
nwidartLaravel ModularNotes
Entities/src/Models/Follow Laravel conventions
Http/Controllers/src/Http/Controllers/Same structure
Console/src/Console/Commands auto-discovered
Providers/src/Providers/Optional, auto-discovery handles most cases
Config/config/Can be published via service provider
Database/Migrations/database/migrations/Auto-discovered
Database/Seeders/database/seeders/Use --module flag
Resources/views/resources/views/Namespaced automatically
Resources/lang/resources/lang/Namespaced automatically
5

Create composer.json for Each Module

Each module needs a composer.json file. You can generate new modules to see the structure:
php artisan make:module example
Example composer.json:
{
  "name": "modules/blog",
  "description": "Blog module",
  "type": "library",
  "require": {},
  "autoload": {
    "psr-4": {
      "Modules\\Blog\\": "src/"
    }
  },
  "autoload-dev": {},
  "extra": {
    "laravel": {
      "providers": [
        "Modules\\Blog\\Providers\\BlogServiceProvider"
      ]
    }
  }
}
6

Update Application composer.json

Add the module as a path repository and require it:
{
  "repositories": [
    {
      "type": "path",
      "url": "app-modules/*",
      "options": {
        "symlink": true
      }
    }
  ],
  "require": {
    "modules/blog": "*"
  }
}
Run Composer update:
composer update modules/blog
7

Update Namespaces

Update all namespace references in your module files:Before:
namespace Modules\Blog\Entities;
After:
namespace Modules\Blog\Models;
Make sure to update all references throughout your codebase, including imports in other files.
8

Migrate Service Providers

Service providers are optional in Laravel Modular due to auto-discovery, but if you need one:Before (nwidart):
namespace Modules\Blog\Providers;

use Illuminate\Support\ServiceProvider;

class BlogServiceProvider extends ServiceProvider
{
    protected $moduleName = 'Blog';
    protected $moduleNameLower = 'blog';
    
    public function boot()
    {
        $this->registerTranslations();
        $this->registerConfig();
        $this->registerViews();
    }
    
    // Custom registration methods...
}
After (Laravel Modular):
namespace Modules\Blog\Providers;

use Illuminate\Support\ServiceProvider;

class BlogServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Register bindings
    }
    
    public function boot(): void
    {
        // Views, translations, and migrations are auto-discovered
        // Only register custom functionality here
    }
}
9

Update View and Translation References

Both packages use namespaced views and translations, but ensure your references match:Views:
// Both packages
view('blog::posts.index')
Translations:
// Both packages
__('blog::messages.welcome')
10

Update Blade Components

Laravel Modular auto-discovers Blade components with namespacing:
FileComponent
src/View/Components/Alert.php<x-blog::alert />
resources/components/button.blade.php<x-blog::button />
11

Run Sync Command

Update your project configuration:
php artisan modules:sync
This will:
  • Add modules to phpunit.xml
  • Update PhpStorm configuration
  • Ensure proper IDE support
12

Remove nwidart/laravel-modules

Once migration is complete and tested:
composer remove nwidart/laravel-modules
Remove the old Modules/ directory if everything is working.

Feature Comparison

nwidart: Modules can be enabled/disabled at runtimeLaravel Modular: All modules are always loaded (by design)If you need dynamic module loading, consider:
  • Feature flags for functionality
  • Route middleware for access control
  • Staying with nwidart/laravel-modules
nwidart commands:
  • php artisan module:make
  • php artisan module:make-controller
  • php artisan module:make-model
  • etc.
Laravel Modular commands:
  • php artisan make:module
  • php artisan make:controller --module=
  • php artisan make:model --module=
  • Uses standard Laravel make: commands with --module flag
nwidart: Built-in asset publishing systemLaravel Modular: Use standard Laravel asset publishing in your service provider:
public function boot(): void
{
    $this->publishes([
        __DIR__.'/../../resources/assets' => public_path('vendor/blog'),
    ], 'blog-assets');
}
nwidart: Custom dependency system in module.jsonLaravel Modular: Use standard Composer dependencies in composer.json:
{
  "require": {
    "modules/core": "*"
  }
}

Benefits of Laravel Modular

Follows Laravel Conventions

You can use all standard Laravel commands and patterns without learning module-specific syntax:
# Standard Laravel commands work with --module flag
php artisan make:model Post --module=blog
php artisan make:controller PostController --module=blog
php artisan make:migration create_posts_table --module=blog

Lighter Weight

Laravel Modular adds minimal overhead:
  • No custom autoloading
  • No runtime module status checks
  • No module-specific configuration formats

Better IDE Support

Because modules are Composer packages:
  • Full IDE autocomplete
  • Native PHPStan/Psalm support
  • Standard debugging tools work immediately

Standard Package Ecosystem

Modules can be easily extracted to standalone packages:
# Module is already a valid Composer package
mv app-modules/blog ~/packages/my-org/blog
# Update composer.json repository path

Common Issues

Module not found after migrationMake sure you’ve:
  1. Added the module to composer.json repositories
  2. Required it in the require section
  3. Run composer update modules/your-module
  4. Run php artisan modules:cache if in production
Classes not auto-discoveredCheck your module’s composer.json:
  • PSR-4 autoloading is correctly configured
  • Namespace matches your directory structure
  • Service provider is registered in extra.laravel.providers
Views/translations not loadingEnsure:
  • Files are in resources/views/ and resources/lang/
  • Module name matches (case-sensitive)
  • Run php artisan modules:clear to clear cache

Getting Help

If you encounter issues during migration:

When to Stay with nwidart

Consider staying with nwidart/laravel-modules if you:
  • Need to dynamically enable/disable modules at runtime
  • Are building a CMS with plugin architecture
  • Require module-specific permissions and access control
  • Have heavily invested in nwidart’s conventions and tooling
Laravel Modular is ideal for teams that want better organization while staying close to Laravel conventions.

Build docs developers (and LLMs) love