Module Structure
Understanding the anatomy of a module
Standard Module Structure
A complete module follows this structure:
Modules/Blog/
├── app/
│ ├── Console/
│ │ └── Commands/
│ ├── Contracts/
│ ├── DTOs/
│ ├── Events/
│ ├── Exceptions/
│ ├── Filament/
│ │ ├── Resources/
│ │ ├── Pages/
│ │ └── Widgets/
│ ├── Http/
│ │ ├── Controllers/
│ │ ├── Middleware/
│ │ └── Requests/
│ ├── Listeners/
│ ├── Livewire/
│ ├── Models/
│ ├── Observers/
│ ├── Policies/
│ ├── Providers/
│ │ └── BlogServiceProvider.php
│ ├── Repositories/
│ ├── Services/
│ └── View/
│ └── Components/
├── config/
│ └── config.php
├── database/
│ ├── factories/
│ ├── migrations/
│ └── seeders/
├── lang/
│ └── en/
├── resources/
│ └── views/
├── routes/
│ ├── api.php
│ ├── web.php
│ └── api/
│ ├── v1.php
│ └── v2.php
├── tests/
│ ├── Feature/
│ └── Unit/
├── composer.json
└── module.json
Minimal Module
Not all directories are required. A minimal module needs:
Modules/Blog/
├── app/
│ └── Providers/
│ └── BlogServiceProvider.php
└── module.json
Key Files
module.json
The manifest file that defines your module:
{
"name": "Blog",
"alias": "blog",
"description": "Blog management module",
"version": "1.0.0",
"priority": 0,
"providers": [
"Modules\\Blog\\Providers\\BlogServiceProvider"
],
"requires": {
"Core": "^1.0"
}
}
Service Provider
The entry point for your module:
namespace Modules\Blog\Providers;
use Illuminate\Support\ServiceProvider;
class BlogServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->mergeConfigFrom(
module_path('Blog', 'config/config.php'),
'blog'
);
}
public function boot(): void
{
// Module boots here
}
}
Namespacing
Modules use PSR-4 autoloading:
| Directory | Namespace |
|---|---|
app/Models |
Modules\Blog\Models |
app/Http/Controllers |
Modules\Blog\Http\Controllers |
app/Services |
Modules\Blog\Services |
database/factories |
Modules\Blog\Database\Factories |
Best Practices
1. Keep Modules Focused
Each module should have a single responsibility:
✓ Blog - Handles blog posts
✓ Comments - Handles comments (separate module)
✗ BlogAndCommentsAndNewsletters - Too broad
2. Use Proper Namespacing
// Good
namespace Modules\Blog\Services;
// Bad
namespace App\Modules\Blog\Services;
3. Leverage Bridges
Don’t manually register routes, views, etc. Let bridges handle it:
// Instead of manually loading routes in ServiceProvider:
// $this->loadRoutesFrom(module_path('Blog', 'routes/web.php'));
// Just create routes/web.php and the RouteBridge handles it
4. Define Dependencies
Always declare dependencies in module.json:
{
"requires": {
"Core": "^1.0",
"Media": "^2.0"
}
}
Helper Functions
// Get module path
$path = module_path('Blog');
$path = module_path('Blog', 'config/config.php');
// Check if module is enabled
if (module_enabled('Blog')) {
// ...
}