Skip to main content
Laravel Modular allows you to customize the stub files used when creating new modules, giving you complete control over the initial structure and boilerplate code.

What are Stubs?

Stubs are template files used by the make:module command to generate initial files for new modules. By default, Laravel Modular creates:
  • composer.json - Package definition
  • Service Provider - Auto-discovery configuration
  • Routes file - Initial route definitions
  • .gitkeep files - For empty directories

Default Stubs

Laravel Modular includes default stubs in vendor/internachi/modular/stubs/:
{
  "name": "StubComposerName",
  "description": "",
  "type": "library",
  "version": "1.0",
  "license": "proprietary",
  "require": {},
  "autoload": {
    "psr-4": {
      "StubModuleNamespace\\StubClassNamePrefix\\": "src/",
      "StubModuleNamespace\\StubClassNamePrefix\\Tests\\": "tests/",
      "StubModuleNamespace\\StubClassNamePrefix\\Database\\Factories\\": "database/factories/",
      "StubModuleNamespace\\StubClassNamePrefix\\Database\\Seeders\\": "database/seeders/"
    }
  },
  "extra": {
    "laravel": {
      "providers": [
        "StubModuleNamespace\\StubClassNamePrefix\\Providers\\StubClassNamePrefixServiceProvider"
      ]
    }
  }
}

Available Placeholders

Stubs support placeholders that are automatically replaced when generating a module:
StubBasePath
string
The absolute path to the module directoryExample: /var/www/app-modules/blog
StubModuleNamespace
string
The PHP namespace for modules (from config)Example: Modules or Acme
StubComposerNamespace
string
The Composer vendor name (kebab-case)Example: modules or acme
StubModuleName
string
The module name in kebab-caseExample: blog or user-management
StubModuleNameSingular
string
Singular form of the module nameExample: blog or user
StubModuleNamePlural
string
Plural form of the module nameExample: blogs or users
StubClassNamePrefix
string
The module name in StudlyCaseExample: Blog or UserManagement
StubComposerName
string
Full Composer package nameExample: modules/blog or acme/user-management
StubMigrationPrefix
string
Timestamp prefix for migrationsExample: 2024_01_15_120000
StubFullyQualifiedTestCaseBase
string
Fully qualified test base class nameExample: Tests\TestCase
StubTestCaseBase
string
Base name of test class (without namespace)Example: TestCase

Configuring Custom Stubs

1

Publish the config file

php artisan vendor:publish --tag=modular-config
This creates config/app-modules.php.
2

Create your stub files

Create a directory for your custom stubs:
mkdir -p stubs/app-modules
3

Configure the stubs array

Edit config/app-modules.php and add your custom stubs:
config/app-modules.php
'stubs' => [
    'src/Providers/StubClassNamePrefixServiceProvider.php' => base_path('stubs/app-modules/ServiceProvider.php'),
    'routes/StubModuleName-routes.php' => base_path('stubs/app-modules/routes.php'),
    'README.md' => base_path('stubs/app-modules/README.md'),
],

Custom Stub Examples

Enhanced Service Provider

Create a service provider with additional boilerplate:
stubs/app-modules/ServiceProvider.php
<?php

namespace StubModuleNamespace\StubClassNamePrefix\Providers;

use Illuminate\Support\ServiceProvider;

class StubClassNamePrefixServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        $this->mergeConfigFrom(
            __DIR__.'/../../config/StubModuleName.php',
            'StubModuleName'
        );
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        $this->loadViewsFrom(__DIR__.'/../../resources/views', 'StubModuleName');
        $this->loadMigrationsFrom(__DIR__.'/../../database/migrations');
        
        if ($this->app->runningInConsole()) {
            $this->publishes([
                __DIR__.'/../../config/StubModuleName.php' => config_path('StubModuleName.php'),
            ], 'StubModuleName-config');
        }
    }
}

Custom Routes Template

Create a routes file with common patterns:
stubs/app-modules/routes.php
<?php

use Illuminate\Support\Facades\Route;
use StubModuleNamespace\StubClassNamePrefix\Controllers\StubClassNamePrefixController;

/*
|--------------------------------------------------------------------------
| StubClassNamePrefix Routes
|--------------------------------------------------------------------------
|
| Here is where you can register routes for the StubClassNamePrefix module.
|
*/

Route::middleware('web')
    ->prefix('StubModuleName')
    ->name('StubModuleName.')
    ->group(function () {
        Route::get('/', [StubClassNamePrefixController::class, 'index'])
            ->name('index');
    });

Module README

Include documentation for each module:
stubs/app-modules/README.md
# StubClassNamePrefix Module

This module handles StubModuleName functionality.

## Installation

This module is automatically loaded via Composer package discovery.

## Structure

- `src/` - PHP source code
- `resources/views/` - Blade templates  
- `routes/` - Route definitions
- `database/` - Migrations, factories, and seeders
- `tests/` - PHPUnit tests

## Routes

All routes are prefixed with `/StubModuleName` and named with `StubModuleName.`

## Testing

```bash
php artisan test --filter=StubClassNamePrefix

License

Proprietary

### Module Config File

Include a config file stub:

```php stubs/app-modules/config.php
<?php

return [
    /*
    |--------------------------------------------------------------------------
    | StubClassNamePrefix Configuration
    |--------------------------------------------------------------------------
    |
    | Configuration options for the StubClassNamePrefix module.
    |
    */
    
    'enabled' => true,
    
    'settings' => [
        'per_page' => 15,
    ],
];
Configure it:
config/app-modules.php
'stubs' => [
    'config/StubModuleName.php' => base_path('stubs/app-modules/config.php'),
    // ... other stubs
],

Initial Controller

Create modules with a default controller:
stubs/app-modules/Controller.php
<?php

namespace StubModuleNamespace\StubClassNamePrefix\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class StubClassNamePrefixController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        return view('StubModuleName::index');
    }
}
Configure:
config/app-modules.php
'stubs' => [
    'src/Controllers/StubClassNamePrefixController.php' => base_path('stubs/app-modules/Controller.php'),
    // ... other stubs
],

Complete Custom Configuration

Here’s a complete example with multiple custom stubs:
config/app-modules.php
<?php

return [
    'modules_namespace' => 'Acme',
    'modules_vendor' => 'acme',
    'modules_directory' => 'app-modules',
    
    'stubs' => [
        // Core files
        'composer.json' => base_path('stubs/app-modules/composer.json'),
        'src/Providers/StubClassNamePrefixServiceProvider.php' => base_path('stubs/app-modules/ServiceProvider.php'),
        
        // Routes and controllers
        'routes/web.php' => base_path('stubs/app-modules/routes.php'),
        'src/Controllers/StubClassNamePrefixController.php' => base_path('stubs/app-modules/Controller.php'),
        
        // Configuration
        'config/StubModuleName.php' => base_path('stubs/app-modules/config.php'),
        
        // Views
        'resources/views/index.blade.php' => base_path('stubs/app-modules/index.blade.php'),
        'resources/views/layouts/app.blade.php' => base_path('stubs/app-modules/layout.blade.php'),
        
        // Documentation
        'README.md' => base_path('stubs/app-modules/README.md'),
        
        // Git
        '.gitignore' => base_path('stubs/app-modules/.gitignore'),
        
        // Keep empty directories
        'database/factories/.gitkeep' => base_path('stubs/app-modules/.gitkeep'),
        'database/migrations/.gitkeep' => base_path('stubs/app-modules/.gitkeep'),
        'database/seeders/.gitkeep' => base_path('stubs/app-modules/.gitkeep'),
        'tests/.gitkeep' => base_path('stubs/app-modules/.gitkeep'),
    ],
];

Stub File Paths

Stub configuration uses two paths:
  • Key: Destination path relative to module root (supports placeholders)
  • Value: Absolute path to stub file (use base_path() helper)

Destination Path (Key)

The destination supports placeholders:
'src/Providers/StubClassNamePrefixServiceProvider.php' => '...'
'routes/StubModuleName-routes.php' => '...'
'config/StubModuleName.php' => '...'

Stub Path (Value)

Use absolute paths with the base_path() helper:
base_path('stubs/app-modules/ServiceProvider.php')
base_path('stubs/app-modules/routes.php')

Using Custom Stubs

Once configured, your custom stubs are automatically used:
php artisan make:module blog
This generates a module using all your custom stubs with placeholders replaced:
app-modules/blog/
├── composer.json
├── README.md
├── config/
│   └── blog.php
├── routes/
│   └── web.php
├── src/
│   ├── Controllers/
│   │   └── BlogController.php
│   └── Providers/
│       └── BlogServiceProvider.php
├── resources/
│   └── views/
│       ├── index.blade.php
│       └── layouts/
│           └── app.blade.php
├── database/
│   ├── factories/
│   ├── migrations/
│   └── seeders/
└── tests/

Best Practices

Store custom stubs in your repository:
stubs/
└── app-modules/
    ├── ServiceProvider.php
    ├── Controller.php
    ├── routes.php
    └── README.md
Always use the correct placeholder format:
// Good
namespace StubModuleNamespace\StubClassNamePrefix;

// Bad - won't be replaced
namespace {{namespace}}\{{class}};
After creating custom stubs, test them:
php artisan make:module test-stub
# Verify all files are created correctly
# Delete the test module
rm -rf app-modules/test-stub
Include a README stub that explains your module structure and conventions.
Only include essential boilerplate. Developers can add more as needed.

Disabling Custom Stubs

To use default stubs again, set the config to null:
config/app-modules.php
'stubs' => null,

Troubleshooting

Placeholders Not Replaced

Ensure you’re using the exact placeholder names:
// These exact strings (case-sensitive):
StubModuleNamespace
StubClassNamePrefix
StubModuleName
StubComposerName

Files Not Generated

Check that:
  1. Stub file paths are absolute (use base_path())
  2. Stub files exist at the specified paths
  3. The stub configuration is properly formatted

Wrong File Permissions

Stub files should be readable:
chmod 644 stubs/app-modules/*

Next Steps

Creating Modules

Learn how to create modules with your custom stubs

Module Components

Create components within your modules

Build docs developers (and LLMs) love