PHPackages                             sinemacula/laravel-modules - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. sinemacula/laravel-modules

ActiveLibrary[Framework](/categories/framework)

sinemacula/laravel-modules
==========================

A lightweight, convention-driven modular architecture package for Laravel - auto-discovers modules as directories with zero manifests, zero boilerplate, and nothing new to learn.

v1.3.0(2w ago)0116Apache-2.0PHPPHP ^8.3CI passing

Since Apr 5Pushed 2w agoCompare

[ Source](https://github.com/sinemacula/laravel-modules)[ Packagist](https://packagist.org/packages/sinemacula/laravel-modules)[ RSS](/packages/sinemacula-laravel-modules/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (6)Dependencies (72)Versions (10)Used By (0)

Laravel Modules
===============

[](#laravel-modules)

[![Latest Stable Version](https://camo.githubusercontent.com/149f5d486919eb0dcd080439735bcfca34dceace901888f1d88d9921626f3a05/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73696e656d6163756c612f6c61726176656c2d6d6f64756c65732e737667)](https://packagist.org/packages/sinemacula/laravel-modules)[![Build Status](https://github.com/sinemacula/laravel-modules/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/sinemacula/laravel-modules/actions/workflows/tests.yml)[![Quality Gates](https://github.com/sinemacula/laravel-modules/actions/workflows/quality-gates.yml/badge.svg?branch=master)](https://github.com/sinemacula/laravel-modules/actions/workflows/quality-gates.yml)[![Maintainability](https://camo.githubusercontent.com/d20f40809b25b58553e65f1df14c56c99b2f02e7c734e6d6c39a0436614e8975/68747470733a2f2f716c74792e73682f67682f73696e656d6163756c612f70726f6a656374732f6c61726176656c2d6d6f64756c65732f6d61696e7461696e6162696c6974792e737667)](https://qlty.sh/gh/sinemacula/projects/laravel-modules)[![Code Coverage](https://camo.githubusercontent.com/9e7739b7dc66ea0a3e7a8fa8ba04186899f7dc0ca696a9b1dc3b807de04d040b/68747470733a2f2f716c74792e73682f67682f73696e656d6163756c612f70726f6a656374732f6c61726176656c2d6d6f64756c65732f636f7665726167652e737667)](https://qlty.sh/gh/sinemacula/projects/laravel-modules)[![Total Downloads](https://camo.githubusercontent.com/77e1c009c46720baa4f0aa4532fd1ad122822d44ce6a0b958bcd5cd45d2f6a92/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73696e656d6163756c612f6c61726176656c2d6d6f64756c65732e737667)](https://packagist.org/packages/sinemacula/laravel-modules)

A lightweight, convention-driven modular architecture package for Laravel. Replaces the standard `app/` directory with a `modules/` directory where each subdirectory is a self-contained module following standard Laravel conventions.

Modules are auto-discovered at boot time and cached for performance. All standard Laravel conventions work inside each module - there is no new API to learn.

How It Works
------------

[](#how-it-works)

Each subdirectory under `modules/` is a self-contained module with its own models, controllers, routes, commands, listeners, events, observers, policies, and more:

```
modules/
├── Foundation/              # Default module - see "Paths and Helpers"
│   ├── Console/             # Commands and schedule
│   └── Providers/           # Service providers
└── Billing/                 # Example domain module
    ├── Console/
    │   ├── Commands/
    │   └── schedule.php
    ├── Events/
    ├── Http/
    │   ├── Controllers/
    │   ├── Requests/
    │   ├── Resources/       # Eloquent API resources - not discovered
    │   └── routes.php
    ├── Listeners/
    ├── Models/
    ├── Observers/
    ├── Policies/
    └── Resources/           # Discovered: views/ and lang/
        ├── lang/
        └── views/

```

Note the two `Resources` directories. `Http/Resources/` holds Eloquent API resource classes and is loaded by PSR-4 like any other class. The module-root `Resources/` is the one the package discovers, and only its `views/` and `lang/`subdirectories are read.

### What Gets Discovered

[](#what-gets-discovered)

ConventionModule PathHow It's LoadedConsole commands`Console/Commands/`Auto-registered via `withCommands()`Scheduled tasks`Console/schedule.php`Auto-registered via `withCommands()`Event listeners`Listeners/`Auto-registered via `withEvents()`Views`Resources/views/`Auto-registered in `ModuleServiceProvider`Translations`Resources/lang/`Auto-registered in `ModuleServiceProvider`Routes`Http/routes.php`Discovered; you wire them in `bootstrap/app.php`Everything else - controllers, requests, resources, events, observers, policies, models, jobs, mail, notifications - works via PSR-4 autoloading. No registration required.

Discovery is per-path and tolerant: a module without a `Listeners/` directory simply does not appear in the listener map. Nothing needs to exist beyond the module directory itself.

Service providers work exactly as they do in a standard Laravel app: register them in `bootstrap/providers.php`. The package does not auto-discover module providers, so you keep full control over their registration order.

### Module Namespaces

[](#module-namespaces)

A module is addressed by a lowercased form of its directory name. `modules/Billing/` registers the namespace `billing`, and views and translations are referenced with the `{module}::{path}` convention:

```
view('billing::invoices.show');
trans('billing::invoices.paid');
```

The namespace is always lowercase, whatever the casing on disk. `view('Billing::invoices.show')` fails with `No hint path defined for [Billing].`

Classes resolve through PSR-4 instead, using the directory name exactly as it is cased. Because `modules/` takes the place of `app/`, the `App\` prefix maps straight onto it:

FileClass`modules/Billing/Models/Invoice.php``App\Billing\Models\Invoice``modules/Billing/Http/Controllers/StatementController.php``App\Billing\Http\Controllers\StatementController`### Generating Classes

[](#generating-classes)

`make:` generators write into `modules/`, because `app_path()` now points there, but they still qualify a bare class name against the application root namespace rather than a module. `make:controller ReportController` creates `modules/Http/Controllers/ReportController.php`, and a path argument does not help - passing `Billing/Http/Controllers/InvoiceController` creates `modules/Http/Controllers/Billing/Http/Controllers/InvoiceController.php`.

Pass the fully qualified class name instead:

```
php artisan make:controller "App\Billing\Http\Controllers\StatementController"
php artisan make:model "App\Billing\Models\Invoice"
```

Those land at `modules/Billing/Http/Controllers/StatementController.php` and `modules/Billing/Models/Invoice.php`. This applies to any generator writing under the application directory; generators targeting `database/` (migrations, factories, seeders) are unaffected and still write to their usual location.

### Artisan Commands

[](#artisan-commands)

CommandDescription`module:make {name}`Scaffold a new module with the standard directory structure`module:list`List all discovered modules and their paths`module:cache`Cache discovered module paths for faster resolution`module:clear`Clear the cached module paths`module:make Billing` creates:

```
modules/Billing/
├── Console/
│   ├── Commands/
│   └── schedule.php
├── Http/
│   ├── Controllers/
│   ├── Requests/
│   └── routes.php
├── Listeners/
├── Models/
└── Resources/
    ├── lang/
    └── views/

```

The `Foundation` module is scaffolded without `Resources/`. It is the default module, so a `Resources` directory there becomes the application's `resource_path()`, and a `Resources/lang` inside it becomes `lang_path()` - which would move your Vite root and orphan the framework's published translations. Create it by hand if that is what you intend.

### Module Caching

[](#module-caching)

Module paths are cached to `bootstrap/cache/modules.php` and integrated into Laravel's `optimize` / `optimize:clear`lifecycle:

```
php artisan optimize        # Includes module:cache
php artisan optimize:clear  # Includes module:clear
```

The cache records the listing of the `modules/` directory it was built from, and is ignored once that listing no longer matches. Laravel caches routes and events *before* any package command runs during `optimize`, so without this a module added since the last `module:cache` would be missing from the route and event caches while the module cache itself looked correct.

Validation covers the immediate entries of `modules/` only, not the contents of each module. Adding or removing a module invalidates the cache; editing a file inside one does not. Any entry appearing or disappearing counts, so a stray file such as `.DS_Store` also sends the next boot down the discovery path until `module:cache` runs again.

`module:make` does not write the cache. It creates a directory under `modules/`, which the validation above treats as a change, so the next boot rediscovers and the new module appears without any further step.

`optimize` also runs `view:cache`, which fails outright on a configured view path that does not exist. A modular application has no `resources/views` directory of its own, and that is where `config('view.paths')` points by default, so the package drops every missing entry from `view.paths` when it registers. Module views are unaffected: they resolve through their own namespace rather than through `view.paths`. The pruned list is what `config:cache` writes too, so an application that adds `resources/views` after an `optimize` run needs the caches rebuilt before it takes effect.

Installation
------------

[](#installation)

```
composer require sinemacula/laravel-modules
```

### 1. Edit `bootstrap/app.php`

[](#1-edit-bootstrapappphp)

Replace the default Laravel application with the modular variant:

```
