nasirkhan/module-manager
Powerful module management for Laravel Starter: track versions, manage migrations, resolve dependencies, and run the full module lifecycle with artisan commands like status, enable, disable, publish, and build.
composer require nasirkhan/module-manager. Requirements are strict: PHP ^8.3, Laravel ^12 or ^13. This is a Laravel Starter companion package, not a generic module system — if you're on stock Laravel plus nwidart/laravel-modules, expect to adapt rather than drop in.php artisan module:help — the package's own command reference and workflows.php artisan module:status — enabled/disabled modules, versions, and dependency state. This is your map of the system.php artisan module:dependencies — what's unsatisfied before you enable anything.php artisan migrate (package modules ship migrations), and php artisan vendor:publish --tag=post-views etc. only for the module you intend to touch.module:publish Post), then composer dump-autoload && php artisan config:clear, and confirm with module:status Post and module:diff Post. Publishing rewrites namespaces from Nasirkhan\ModuleManager\Modules\Post\... to Modules\Post\..., so you now own that code.Consume-in-vendor vs. publish-and-own. Keep package modules vendored while you're not changing them; publish only the ones you fork. Once published, package updates no longer reach that module — module:diff {module} --detailed becomes your upgrade check, and re-running vendor:publish --tag=post-migrations is a manual reconciliation step, not a merge.
Scaffolding your own modules. module:build Invoice generates the standard tree (Config/, database/migrations, Http/, routes/, Tests/, ...). Fill in module.json deliberately:
{
"name": "Invoice",
"alias": "invoice",
"version": "1.0.0",
"priority": 0,
"requires": ["Category", "Tag"]
}
Use priority as a load-order contract in a starter app: core/auth/permission modules at 10, shared UI/menu at 5, content modules at 0. requires gives you dependency gating for free in module:status/module:dependencies.
Upgrade workflow for shipped modules — treat this as a fixed ritual after every composer update:
php artisan module:detect-updates # what changed
php artisan module:check-migrations # unpublished/pending migrations
php artisan vendor:publish --tag=post-migrations
php artisan migrate
Use module:track-migrations --force to re-baseline after you've confirmed and applied what's pending — it records current state as the new baseline.
Gate your own bootstrapping on module state. Wrap module-dependent registration instead of assuming presence:
use Nasirkhan\ModuleManager\Services\ModuleVersion;
$modules = app(ModuleVersion::class);
if ($modules->dependenciesSatisfied('Invoice')) {
// register event listeners, routes, policies
}
foreach ($modules->getModulesByPriority() as $module) {
// build a nav/menu or admin dashboard listing
}
Custom tooling on top of the services. ModuleVersion (getVersion, getDependencies, dependenciesSatisfied, getModulesByPriority) and MigrationTracker (trackModuleMigrations, getNewMigrationsSinceLastCheck, getPendingMigrations, hasUpdates) are the stable programmatic surface — good candidates to wrap in your own deploy or module:audit command rather than parsing CLI output.
Testing per module. module:make-test Post PostPublishesTest [--unit] drops into the module's Tests/Feature or Tests/Unit. Keep module tests inside the module so they travel with it when published/removed.
Feature toggling in environments. module:enable/module:disable is a cheap way to keep a module's code deployed while removing its routes/views/providers in a given environment — remember its tables and data persist either way.
module:publish, any namespace rewrite, or adding a module: composer dump-autoload, php artisan cache:clear, php artisan config:clear. Skipping this makes modules silently absent from module:status.module.json is the source of truth for version and dependency metadata. If you edit a published module, bump version there — otherwise module:diff, module:detect-updates, and the migration baseline lie to you.module:track-migrations --force overwrites the baseline. It can mask genuinely pending migrations. Always run module:check-migrations / detect-updates before forcing a re-track.requires are matched, so casing matters ("Post", not "post" — the alias is a separate field). Watch for accidental cycles; a requires loop will make priority ordering meaningless.spatie/laravel-activitylog ^5 and intervention/image-laravel ^4 as direct deps (used by the Post model and the Jodit image connector). You may remove your own duplicates, but if your app pins different majors you'll get a conflict — check composer why before upgrading.module:remove deletes the module directory outright, and a published module isn't recoverable from vendor/ without re-publishing and re-applying your edits. Commit before publishing, removing, or --force-tracking anything.module:build output will need hand-editing, and the shipped modules may assume auth/menu scaffolding you don't have.module:dist {module} --detailed shows exactly how your published copy drifted from the package — that's your merge brief after composer update, not a raw git diff of vendor/.{alias}-migrations, -views, -config, -lang), module.json fields, and the two services. There's no documented event/hook system, so prefer wrapping the services in your own commands over patching vendor files.UPGRADE.md/CHANGELOG.md on every bump, and keep a fresh module:diff/migration baseline before and after upgrading.How can I help you explore Laravel packages today?