edalzell/laravel-features
A lightweight feature flag package for Laravel. Define named features in config, toggle them per environment or user, and check availability anywhere in your app with a simple API—ideal for gradual rollouts, beta access, and shipping code without new deploys.
Architecture fit This package adds a feature module layer on top of Laravel's existing service-container and service-provider model: each feature owns its own routes, commands, translations, seeders, migrations, and declared dependencies. v1.1.0 materially strengthened that fit — feature-scoped console commands (#107) and translations (#108) moved it from "routing convention" to "module boundary." v1.2.0 extends the boundary outward with a boot hook extension point (#115): third-party or cross-cutting code can now attach behaviour to a feature's boot phase without editing the feature itself. For a TPM this is the second interesting release in a row — it is the difference between a module system you structure code with and a module system other packages can integrate against. That is the point at which the package starts to look like a platform primitive rather than an internal convention, and it is also the point at which its boot semantics become something we have to reason about and test, not just adopt.
Integration feasibility Still low-to-moderate. Composer install plus a published config and a features directory; no external service, no data store, no queue or scheduler dependency. The 1.2.0 changes are additive: an extension point we can choose to ignore, plus an internal review pass. We do not have to adopt hooks on day one, and the 1.1.0 capabilities we were already buying (per-feature command registration, translation loading, seeder discovery fix) are unchanged in shape.
Two caveats sit on the review pass (#117). It touches registry, discovery, route groups, and disk — four of the five subsystems our spike is meant to validate — one minor release after those subsystems were introduced. That is normal hardening, but it means our staging validation must be run against 1.2.0 specifically, not inherited from a 1.1.0 spike. The mention of disk is also the first indication of a filesystem concern in this package; the previous assessment assumed zero infrastructure footprint, and we should confirm whether that is an internal path-resolution fix or something that expects a configured disk.
Technical risk
Key questions
Stack fit
Native Laravel, Composer-only, no frontend footprint. The one thing to re-verify post-#117 is the filesystem assumption — if the package now expects a configured disk or a writable path outside storage/, that is a small but real deployment constraint we should catch in staging rather than in production. It remains complementary to, not a replacement for, package-level modularity; we should still not run two discovery systems over the same directories. Hooks give us a sanctioned way to inject cross-cutting behaviour into features, which is preferable to the alternative we would otherwise reach for (editing each feature or adding a custom loader).
Migration path
app/ — feature extraction is incremental and each slice is independently revertible.^1.2 so we are not carrying a version we have already validated out of.Compatibility
Validate against our other discovery-based packages (Livewire/Volt/Folio-style auto-registration) and against config:cache, route:cache, and optimize in staging before production. Confirm command registration does not collide with first-party artisan commands. Confirm translation namespacing matches our i18n tooling and does not break string extraction. New: if we adopt hooks, confirm they run under a fully warmed cache in the same order as on a cold boot, and that a hook registered by a third-party package cannot silently outrank our own.
Sequencing
optimize + route:cache + config:cache in staging; confirm no duplicate-signature boot failures and no disk-path errors.Maintenance Low ongoing cost: small codebase, low release cadence, automated dependency bumps. Cost is in governance, not upkeep — we need an internal owner for the feature conventions, and now also for the hook policy, otherwise hooks become an unowned cross-cutting layer that nobody can safely remove. The #117 review pass is a positive signal on maintainer diligence but also a reminder to read the diff rather than the release notes.
Support Community-supported with a single dominant maintainer. The exit calculus is now slightly worse than at 1.1.0: conventions are easy to inline, but a published hook contract invites third-party usage that we would have to shim if we forked or inlined. That exit cost should be documented before broad adoption and before we allow hooks into shared packages, not after.
Scaling
Two scaling axes, plus a new one. Feature count: boot-time and discovery overhead grow with N; production discovery caching is mandatory, not optional. Translation volume: per-feature translation loading increases memory and lookup precedence complexity — measure past a few dozen features. Hook count: unlike the other two, hooks scale with integration surface rather than feature count, and each hook is code in the boot path on every request — this is the axis most likely to produce a latency surprise, and the one with the least visibility today. Command registration also grows the artisan command list, affecting artisan list responsiveness and help output quality.
Failure modes
::class case is fixed in 1.1.0, but dependency ordering between seeders remains a sharp edge in non-production environments.Ramp-up Modest for anyone fluent in Laravel service providers — the concepts map directly. The real ramp-up is the discovery mental model: engineers must internalize that commands, translations, routes, and seeders are picked up implicitly, and know where to look when something is not registered. If hooks are adopted, add a second mental model — "code that runs because a feature booted, not because a file was found." Budget a short internal write-up plus one exemplar feature and one exemplar hook in the repo; that artifact will carry more weight than the package docs.
TPM recommendation
Hold the current ^1.1 pin, run a one-day regression check of the existing spike branch against 1.2.0 (registry, discovery, route groups, disk), then pin forward to ^1.2 if it is clean. Do not introduce boot hooks during the first wave — treat them as a second-wave decision gated on documented ordering and failure semantics. Do not standardize the whole codebase until the first two slices have shipped and the discovery model has survived one on-call rotation.
How can I help you explore Laravel packages today?