drivkraft/interlock
drivkraft/interlock is a Laravel package that adds lightweight interlocking primitives to help coordinate concurrent work, prevent overlapping jobs, and guard shared resources against race conditions with simple, reliable locks.
Architecture fit. Interlock is a modular-monolith toolkit: it turns each folder under modules/ with a composer.json into a self-contained unit with its own PSR-4 namespace, and then auto-wires the Laravel surface area (providers, routes, views, translations, Blade components, commands, listeners, migrations, factories). That is a good architectural match for the common TPM-level goal of giving teams ownership boundaries without paying the distributed-systems tax of microservices. Critically, it is convention over configuration rather than a new runtime — modules are still ordinary Laravel service providers, so the exit cost is low and the blast radius of adoption is contained. The Interlock facade (modules(), module(), moduleForClass(), moduleForPath()) gives an introspection seam that makes boundary rules enforceable in code review and static analysis, which is the piece most home-grown modular setups lack.
Integration feasibility. Mechanically straightforward: add the package, allow the Composer plugin, create modules/, configure interlock.php, and start scaffolding. No new runtime, no sidecar, no infrastructure. Two frictions are worth naming up front:
wikimedia/composer-merge-plugin is the load-bearing dependency for autoloading. It requires allow-plugins entries in composer.json and interacts with lockfile generation in ways that can surprise CI. It is the part of this package most likely to cause an unplanned afternoon. It does buy correct behaviour under optimised and authoritative classmaps, which is the right production posture — that is a genuine point in its favour.Technical risk.
| Risk | Severity | Note |
|---|---|---|
| PHP 8.5 / Laravel 13 floor | High | Hard blocker unless your platform roadmap is already there. Confines adoption to greenfield or explicitly forward-looking projects. |
| Composer plugin dependency | Medium | allow-plugins, CI auth, merge semantics; a supply-chain and build-reproducibility consideration. |
Generator surface (30 make:* counterparts) |
Medium | These mirror Laravel internals and will drift with every framework release. Ongoing maintenance tax sits with the package, but your upgrade cadence inherits its release lag. |
| Convention magic / implicit discovery | Medium | Powerful defaults, but debuggability suffers when something silently isn't discovered. Mitigated by module:list and the discovery toggles. |
| Ecosystem maturity | Medium | v1.0.0 with a bleeding-edge floor implies a young project. Maintainer count, backing, and BC policy are unknown from the notes. |
Optional integrations (Livewire, laravel-actions, laravel-data) |
Low | Conditional wiring means no hard dependency; good design. |
Key questions to put to the maintainers before committing:
module:list purely informational?nwidart/laravel-modules?--tests scaffolds, but the harness story isn't described.)Stack fit. Native fit for a Laravel app of any size that has, or wants, internal boundaries. It is not a fit for a monolith with no intention of modularising, and not a fit for teams who cannot move to Laravel 13. The optional Livewire namespacing (billing.pages::) is a thoughtful touch for teams already using Livewire; ignore it otherwise. The conditional module:action / module:data generators mean the package doesn't force an opinion on action or DTO patterns — good for incremental adoption.
Migration path. Do not treat this as a big-bang restructure. The viable path is incremental extraction: leave app/ untouched, stand up one module, and grow outward.
module:make --all, and exercise the full discovery surface (routes, views, translations, commands, migrations, factories). Time-box it. The goal is to surface CI and deploy friction, not to build anything.composer install --optimize-autoloader --classmap-authoritative and php artisan optimize in a clean CI container. Confirm module:cache fires and the app boots with a cold cache. Then corrupt the cache deliberately and confirm the failure mode is legible.composer.json, cross-module communication rules, and where shared contracts go. Interlock gives you the mechanism; the governance is yours.interlock.discover and interlock.routes tuned to drop anything unused.Compatibility. Verify against your full dependency set, especially anything that registers its own service providers or relies on app/ paths by convention. Run the whole existing test suite inside a module-aware codebase before trusting the result.
Sequencing note. Do the PHP/Laravel upgrade first, then adopt Interlock. Doing both at once conflates two large sources of failure and makes rollback of either impossible.
Maintenance. The steady-state cost is low — module code is ordinary Laravel code. The variable cost is upgrade lag: every Laravel release that changes a make:* signature, a discovery convention, or the service-provider lifecycle creates a gap between your desired upgrade and Interlock's supported version. Because the package sits at the very front of the version curve today, you are betting on it staying there. Put it on the same watch list as your framework upgrade planning, and budget for the possibility of patching or forking the generator layer.
Support. Unknown from the release notes and a material unknown generally. Before adopting, establish maintainer responsiveness (issue/PR turnaround), whether there is commercial backing, and whether a security-disclosure process exists. The composer-merge-plugin dependency inherits its own support posture, which is a second thing you don't control.
Scaling. Favourable. Discovery is manifest-cached and hooks into optimize/optimize:clear, so the boot-time cost is amortised in production and the cache is refreshed by the standard deploy step rather than a bespoke one. Authoritative-classmap compatibility means autoloading performance is as good as a flat app. The thing that scales worse than the runtime is the human scaling: 30 generators and a wide discovery surface mean more conventions for new joiners to absorb, and more places for a module to be silently wrong.
Failure modes to instrument and document.
optimize didn't run or ran against a stale artifact. Make module:cache an observable deploy step.composer dump-autoload didn't run; works locally, fails in production.composer.json, or wrong PSR-4 entry means the module simply doesn't load. No error. module:list in CI is a cheap guard: assert the expected module count and names.composer install, particularly with lockfile mismatches in CI.moduleForClass() returning null during early boot or for vendor classes — callers must handle null rather than assume.Ramp-up. Low for anyone fluent in Laravel — a day of reading and a scaffolded module is enough to be productive. The friction is in the unlearning: developers accustomed to app/Http/Controllers need the module layout and the --module flag to become reflexive, and reviewers need the boundary rules written down or the modules will erode into a distributed app/. Budget a short internal walkthrough, a written convention doc, and one exemplar module that everyone copies.
How can I help you explore Laravel packages today?