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

Modular Laravel Package

internachi/modular

internachi/modular is a module system for Laravel applications. It lets you create modules in an app-modules/ directory using Composer path repositories for autoloading and Laravel package discovery for initialization, plus minimal tooling to fill the gaps.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require internachi/modular. Laravel package discovery registers the service provider automatically; there is no manual provider wiring step.
  • Immediately publish and edit the config: php artisan vendor:publish --tag=modular-config. The single most important setting is the module namespace. The default Modules\ works, but choose your organization namespace (e.g. Acme\) before you create real modules — retrofitting namespaces across dozens of modules later is painful.
  • Scaffold the first module with php artisan make:module billing. This creates app-modules/billing/ with composer.json, src/, tests/, routes/, resources/, and database/, and edits the root composer.json to add a path repository plus a modules/billing:* requirement.
  • Run composer update modules/billing as prompted. The module is not autoloadable until this runs — this is the step people forget.
  • Run php artisan modules:sync once to wire up phpunit.xml (adds a Modules test suite) and PhpStorm config. It is idempotent and safe to re-run, so add it to post-autoload-dump in the root composer.json.
  • Where to look first: the generated module's composer.json (namespace + dependency contract) and its service provider under src/. Then php artisan modules:list to confirm what the package actually sees.
  • First real use case: pick one cohesive domain out of an overgrown app/ — Billing, Notifications, Reporting — and move its models, migrations, factories, policies, listeners, and routes into a module. Because the module is a normal Composer path repository and a normal Laravel package, everything inside keeps using stock Laravel conventions. The value is organizational, not a new runtime paradigm.

Implementation Patterns

  • Scaffold inside the module, not in app/. Use the --module= flag on the familiar generators: make:model Invoice --module=billing, make:controller InvoiceController --module=billing, make:migration, make:factory, make:policy, make:listener, make:command, make:test, etc. Custom stubs still apply, so the generated code matches your house style. This is the primary day-to-day workflow — you rarely hand-create files.
  • Lean on auto-discovery. Commands, migrations, factories, policies, Blade components, and event listeners are discovered from modules like any Laravel package. A module's Artisan commands show up without registration; migrations run with php artisan migrate; factory() resolves module factories; policies attach to module models. Treat the module's service provider as the place for the few things that genuinely need explicit registration (routes, views, custom bindings).
  • Namespaced views and translations. Blade components are addressable as <x-billing::invoice-card />, <x-billing::nested.one />, and anonymous components mirror their file paths. Translations use __('billing::messages.welcome'). This keeps cross-module template references explicit and prevents accidental coupling.
  • Seed per module. php artisan db:seed --module=billing targets Acme\Billing\Database\Seeders\DatabaseSeeder; adding --class=InvoiceSeeder --module=billing resolves inside the module's Database\Seeders namespace. Use this in local setup and test fixtures rather than reaching into module internals from the root seeder.
  • Test inside the module. Tests live in app-modules/billing/tests/ and run under the Modules suite added by modules:sync. Because Composer does not support autoload-dev for non-root packages, tests are autoloaded from the module's main autoload block — structure test namespaces accordingly and don't expect autoload-dev semantics.
  • Cross-module dependencies go through Composer. If Billing needs something from Core, declare modules/core in Billing's composer.json and import the class. Do not reach across module directories with relative includes. Keeping dependencies explicit in each module's composer.json is what makes future extraction to a standalone package realistic.
  • Customize the scaffold once. Publish the module config (app-modules.php) and edit the stubs with the provided placeholders (StubModuleNamespace, StubClassNamePrefix, StubMigrationPrefix, StubFullyQualifiedTestCaseBase, etc.). Teams that skip this end up hand-fixing every generated file; teams that do it get consistent modules for free.
  • Deployment pattern. Run php artisan modules:cache during deploy to cache module discovery, and php artisan modules:clear when adding or removing modules locally. Pair with modules:sync in post-autoload-dump so phpunit.xml and IDE config never drift.
  • Incremental adoption. You do not need to modularize everything. Create modules for the domains that are large or likely to be extracted, leave the rest in app/, and let both coexist. Modules are just path-repository packages; there is no all-or-nothing commitment.

Gotchas and Tips

  • make:module is a two-step operation. It edits the root composer.json but does not run Composer. Until you run composer update modules/<name>, autoloading fails with confusing class-not-found errors. Any CI or onboarding script that scaffolds modules must run the update.
  • Set the namespace before you have modules. Changing the module namespace later means editing every module's composer.json, every namespace declaration, and the root path require entries. Decide the organization namespace on day one.
  • Module cache can mask changes. After adding, renaming, or deleting a module, run modules:clear (or re-run modules:cache) if discovery looks stale. If modules:list disagrees with the filesystem, clear the cache and composer dump-autoload before debugging anything else.
  • modules:sync is additive and idempotent. It will add missing phpunit.xml suite entries and PhpStorm config, and it now marks modules as excluded paths in PhpStorm to avoid double-registration in the IDE. Re-run it after changing editor or test configuration; it won't clobber existing settings.
  • make:model --all is only partially supported. Don't assume it generates the full Laravel set (migration, factory, seeder, controller, policy) inside a module. Generate the pieces explicitly with separate --module= calls when correctness matters.
  • db:seed --module expects the module's seeder namespace. Passing a bare class name resolves under Acme\<Module>\Database\Seeders. If seeding silently fails, check the namespace assumption first.
  • Route registration isn't free. The scaffold creates routes/, but routes are not in the documented auto-discovery list. Verify the generated service provider and register route files explicitly if needed — this is the most common gap when a new module's endpoints 404.
  • Migrations across modules share one timeline. Laravel's migrator runs all module migrations together. Keep timestamps sensible and use StubMigrationPrefix to keep names distinguishable; be careful when a module migration alters a table created by another module, since ordering is timestamp-based.
  • This is not a dynamic module system. There is no enable/disable, no marketplace-style dynamic loading, and no per-module activation UI. Modules are Composer dependencies of the app. If you need runtime toggling for third-party plugins, nwidart/laravel-modules is the better fit; choose Modular for organization.
  • Debugging checklist for "my module isn't loaded": confirm the path repository entry in root composer.json, confirm modules/<name> is required, run composer update modules/<name>, run modules:clear, run composer dump-autoload, then modules:list. That sequence resolves nearly every discovery issue.
  • Windows path quirks are mostly fixed but worth noting. Path normalization was improved in 1.10.0; if a module path fails to load on Windows, check for mixed separators in the generated root composer.json before chasing anything else.
  • Treat the module composer.json as a contract. If you hope to extract a module into a standalone package later, keep its dependencies complete and avoid referencing app-specific helpers. The organization namespace plus an honest dependency list is the whole extraction strategy — the package's conventions do the rest.
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.
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus