Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Modular Laravel Package

idel/laravel-modular

idel/laravel-modular brings a structured module system to Laravel, letting you split large applications into self-contained packages with their own routes, views, migrations, config, and service providers, so features stay organized, reusable, and easy to enable or disable.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with a pinned constraint — the last tagged release is from December 2023, so treat the version you test as the version you ship:

composer require idel/laravel-modular:^1.0

Before writing code, check two things in vendor/idel/laravel-modular/:

  1. composer.json — the illuminate/* constraints tell you whether the package will actually run on your Laravel version (especially Laravel 11+, where the skeleton and service-provider bootstrapping changed). If it lags, either stay on the supported version or plan to fork.
  2. The service provider — note the provider FQCN; you'll need it for publishing and for bootstrap/providers.php / config/app.php.

Then publish the scaffolding:

php artisan vendor:publish --provider="Idel\Modular\ModularServiceProvider"

That gives you config/modular.php, which is the real entry point. Read it top to bottom before anything else — it typically controls the module base path (modules/ or app-modules/), the PHP namespace for modules, stub locations, and (critically) whether module providers are auto-discovered or must be listed explicitly.

First use case: pick one cohesive slice of the app — billing, notifications, a reporting subsystem — and move it wholesale. Do not start by modularizing the whole codebase. A good first module has its own routes, a handful of migrations, and few inbound dependencies from the rest of the app. That way you validate the package's route/migration/view registration against something real, with a small blast radius.

If the package ships make commands, the flow is usually:

php artisan modular:make Billing       # or module:make, check `artisan list`
composer dump-autoload                 # almost always required after scaffolding

Implementation Patterns

Treat the module as a mini-Laravel app. The layout that works:

modules/Billing/
├── Providers/BillingServiceProvider.php
├── Http/Controllers/
├── Routes/web.php
├── Routes/api.php
├── Database/Migrations/
├── Resources/views/
├── Config/billing.php
└── Tests/

Inside the module provider's boot(), register the pieces explicitly rather than hoping discovery handles it:

$this->loadMigrationsFrom(__DIR__.'/../Database/Migrations');
$this->loadViewsFrom(__DIR__.'/../Resources/views', 'billing');
$this->mergeConfigFrom(__DIR__.'/../Config/billing.php', 'billing');

Route::middleware('web')
    ->prefix(config('modular.route_prefix'))
    ->name('billing.')
    ->group(__DIR__.'/../Routes/web.php');

Guard your route names and prefixes. Modules sharing a flat namespace collide fast. Always name routes (billing.invoices.index) and namespace config/views (config('billing.gateway'), view('billing::index')).

Cross-module communication: events and contracts, never direct class imports. If Billing needs data from Orders, define an interface in a small Core/Shared module and bind the implementation in the owning module's provider. Otherwise you get a module graph that is just a directory graph.

// modules/Core/Contracts/OrderLookup.php
interface OrderLookup { public function recentFor(int $userId): Collection; }

Register module console commands and schedules in the module provider, not in routes/console.php. Same for queued jobs — a module that works in HTTP but breaks under queue:work is usually a missing commands() or a class not in the autoload map.

Testing: add a testsuite per module in phpunit.xml pointing at modules/*/Tests, and make sure your base TestCase migrates all module migration paths. A module whose tests only pass when run in isolation is not done.

Deployment: modules must be enumerated deterministically. If auto-discovery scans the filesystem, confirm the order is stable and that config:cache + route:cache still produce the same route table as local dev — diff route:list output between environments once.

Gotchas and Tips

  • Autoload is the #1 failure mode. New module class → Class not found → run composer dump-autoload. If modules aren't covered by a psr-4 entry in the root composer.json, check whether the package registers it at runtime; runtime spl_autoload_register works in HTTP but silently fails in optimized/--classmap-authoritative deployments.
  • config:cache hides new module config. Adding modules/Billing/Config/billing.php won't appear until php artisan config:clear. Same class of bug for view caches after moving Blade files.
  • Route caching with dynamically-registered routes. If module providers are only loaded conditionally, route:cache can bake an incomplete table. Verify with php artisan route:list --path=billing after caching.
  • Migration ordering across modules. Laravel sorts by filename timestamp globally; two modules generating migrations in the same second can interleave. Keep filenames timestamp-prefixed and don't create a foreign key in module A to a table in module B unless you control creation order (or drop the FK and enforce it in code).
  • Case sensitivity. Namespace segments must match directory names exactly. It works on macOS and breaks on Linux CI — a classic module-package trap.
  • Debugging checklist: php artisan about, php artisan route:list --path=<module>, php artisan event:list, and dump the package's module registry (often app('modular')->all() or a Modular facade) to confirm what it thinks is installed. Nine times out of ten the registry disagrees with the filesystem.
  • Extension points worth knowing: custom stubs (publish and edit them so every new module starts with your conventions baked in), and the module namespace/path config — changing path after modules exist means updating the root composer.json autoload and re-dumping.
  • Adoption risk is the real gotcha. 15 stars, zero dependents, last release 2023. Do not let package-specific APIs leak into module code. If each module is just a PSR-4 namespace plus a ServiceProvider that registers routes, migrations, views, and config, you can delete the package in an afternoon and replace it with a 20-line ModuleServiceProvider base class. That escape hatch is worth designing for on day one — it also makes the package's value proposition (convention and make commands) the only thing you're actually depending on.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle