panicdevs/modulite
Modulite automatically discovers and registers Filament panel providers, resources, pages, and widgets across modular Laravel apps. Supports nwidart/laravel-modules and panicdevs/modules, with file-based caching and commands for production performance.
Architecture fit. Modulite is a convention layer that sits between two things we would already be running: a modular Laravel layout (nwidart/laravel-modules or panicdevs/modules) and one or more Filament panels. It replaces hand-maintained registration in PanelProvider files with filesystem convention — the difference between "new module = a diff touching shared provider files owned by someone else" and "new module = drop files in the expected directory." That is a real win only under two preconditions: modules are already our unit of feature delivery, and we run more than one Filament panel or expect to. Value scales roughly with modules × panels × frequency of module addition. With one panel and a handful of stable modules, the package adds a moving part without removing meaningful toil. The design deliberately mirrors first-party Laravel idioms — published config, a bootstrap/cache/modulite.php artifact, a modulite:cache command alongside optimize, an optimize:clear interaction, and a modulite:status diagnostic — which means it slots into our existing deploy and runbook mental model rather than arriving as a bespoke framework.
Integration feasibility. Mechanically trivial and low-blast-radius: composer require panicdevs/modulite, publish the config, add ModulitePlugin::make() to each panel's plugins([...]), run modulite:cache at deploy. No migrations, no database tables, no external services, no background worker, no runtime daemon. Removal is symmetric — drop the plugin line and the package — with no data residue. The entire integration surface is one config file, N panel provider lines, and one deploy step.
Technical risk.
fail_silently is the production default) returns an empty discovery set, which is then cached with ttl = 0 (never expires), taking every panel offline until an operator manually clears the cache. That the identical fix appears in two consecutive releases suggests either a regression or a re-ship — either way, this is a discovery layer that fails closed on the critical path of the admin UI. Our mitigation is not "trust the fix," it is deploy-time verification.composer update drift.Filament/{Panel}/Resources|Pages|Widgets) and class suffixes (Resource, Page, Widget) determine registration. A misplaced file doesn't error — the component simply doesn't appear. This converts structural mistakes into "someone notices a missing menu item" tickets.Key questions.
modules.approach setting (nwidart vs panicdevs) plus scan_only_enabled / respect_module_priority semantics?bootstrap/cache/modulite.php) get built per-release in CI, or generated on first request in production? Only the former is acceptable to us.php artisan optimize ordering in our pipeline, and is modulite:cache idempotent and safe to run twice?Stack fit. Clean, provided our stack is Laravel 11/12 on PHP 8.2+, Filament 4 (or 5 if we accept the v1.1.1+ line), and either of the two supported module managers. The package introduces no new runtime dependencies beyond Filament itself and adds nothing to the request path beyond a single file include on the warm path.
Migration path. There is no formal migration, but there is a good low-risk adoption pattern that the package itself enables:
Filament/ component directory currently registered by hand. This is the work item most likely to be underestimated — the discovery config must be written to match what we already have, not the README's example.components.registration.auto_register => false. This is the key safety valve: the package will discover without registering, so we can diff the discovered set against the manually registered set and prove parity before any behavior changes. Any component in the manual set but absent from discovery is a convention mismatch we must fix or explicitly exclude.admin). Keep the manual registrations in place for a release; duplicate registration of the same component is the visible symptom to watch for, and it is recoverable.Compatibility. Pin the package version explicitly in composer.json (not ^1.0). Add Modulite to the same upgrade gate as Filament: a Filament major bump requires verifying a Modulite release claims support for it. Verify Filament 4 vs 5 support line matches what we deploy before writing config, since the README's requirements line and the release notes disagree on the supported Filament major.
Sequencing (dependency-ordered).
modulite:status --vvv locally and diff against manual registrations.auto_register => false, then true.modulite:cache runs after artisan optimize, artifact ships with the release, and a post-deploy assertion confirms discovery is non-empty.optimize:clear path is documented for hotfixes.Maintenance. The steady-state maintenance cost is low but not zero: config in version control, a deploy step, and an upgrade gate. The real maintenance exposure is upstream — one maintainer, ~22 stars, zero dependents, README-only docs. We should budget for the possibility of becoming the maintainer of our own fork. That is acceptable for a ~1k-line convention layer; it would not be acceptable for something with a database schema. Keep the integration small enough that a fork is a weekend, not a quarter.
Support. Self-serve only: README, GitHub issues, no docs site, no commercial support, no SLA. Internal enablement burden falls on whoever owns the pilot — realistically 0.5–1 engineer-day for configuration and parity verification, plus ~0.5 day of pipeline work, plus a written internal runbook covering "panels disappeared" → check cache → modulite:cache --force.
Scaling. Documented benchmarks are modest and credible for a file-based cache: ~1–20ms cold scan depending on module count, ~1–2ms warm, sub-1ms overhead when optimized. This scales fine to dozens of modules; the cost driver is module count at cold scan, which is exactly what the cache exists to eliminate in production. Horizontally this is benign — one file per release, no shared state, no coordination between app servers. The genuine scaling concern is cache lifecycle at scale: every deploy must rebuild the artifact, and every server must receive the rebuilt one atomically with the code. If we run N app servers behind a load balancer with a shared bootstrap/cache that isn't per-release, we can serve a stale map against new code.
Failure modes (ranked by business impact).
ttl = 0). Impact: total admin UI outage. This has happened upstream at least twice. Mitigation: post-deploy assertion that discovery is non-empty; monitoring on admin route availability; documented hotfix via modulite:cache --force; consider a non-zero TTL in production rather than trusting ttl = 0.modulite:cache a mandatory, non-optional pipeline step, run against the built artifact.bootstrap/cache isn't writable at build time. Mitigation: build in CI, never at runtime.fail_silently defaults to true in production — correct for availability, bad for observability. Mitigation: enable modulite:status --vvv in a scheduled or post-deploy check and alert on anomalies, rather than relying on users reporting missing menus.Ramp-up. Developer ramp-up is genuinely small: add a directory, name the class correctly, done. The learning curve is concentrated in two places — the panel-to-directory mapping (Filament/{panel}/..., which is case-sensitive and easy to get wrong) and the cache lifecycle in CI. Both are one-time, both belong in an internal runbook rather than in each developer's head. Expect a new team member to be productive with the convention on day one and to understand the cache behavior only after their first deploy.
Recommendation framing. This is a good-fit, low-cost, reversible integration whose risk is almost entirely concentrated in one failure mode and one governance fact: an empty-result cache that can black out the admin panel, maintained by a single author with no dependent projects. If we adopt, adopt deliberately — with the pinned version, the parity pilot, the deploy-time cache build, and a non-empty assertion in the pipeline. If the current pain is "we maintain panel registrations by hand across many modules," it earns its place. If the pain is speculative, defer; the package will be no less adoptable at 100 stars, and considerably better understood.
How can I help you explore Laravel packages today?