hotflo/feature-toggle-bundle
hotflo/feature-toggle-bundle adds a simple feature-flag layer to PHP applications, letting teams enable or disable features at runtime without redeploying. Define toggles, check them in code, and roll out changes gradually with less risk.
Architecture fit. The naming in this repo is misleading and that matters for planning: hotflo/feature-toggle-bundle is a Symfony2 bundle, not a Laravel package. The Laravel-style description (Blade directives, middleware, config-driven flags) does not match the artefact — the code is a Bundle subclass plus a DI container extension, service definitions, and framework config. Laravel has no counterpart to any of that. What is reusable is the underlying JoshuaEstes/FeatureToggle library and its concept — a named toggle resolved against a context — and that concept is now available from a first-party source (Laravel Pennant). From a product perspective the deliverable here is a pattern reference, not an adoptable dependency.
Integration feasibility. Low without a fork, and the fork yields nothing Pennant does not already give us. A realistic spike: strip bundle wiring, re-express services as a Laravel ServiceProvider with a published config file, replace Symfony event-dispatcher/kernel hooks with Laravel equivalents, audit the transitive dependency set, and write tests. Estimate 3–5 engineering days for a proof of concept plus hardening — spent reproducing a capability the framework ships. Only worth it if there is existing Symfony2 code in the estate consuming this bundle; otherwise the correct move is to read it and move on.
Technical risk. High, and mostly non-technical. Symfony 2.8 went end-of-life in November 2018 and receives no security patches. The dependency graph almost certainly pins Symfony 2.x/3.x components, which will collide with Laravel 10/11/12's requirement on Symfony 6.x/7.x — Composer resolution likely fails before a line of integration code is written. Zero stars and zero dependents means no downstream validation against a modern runtime, no triaged issues, and no evidence the package works outside the author's original context. That combination will not survive a modern dependency-scanning gate in procurement or security review, and it shouldn't.
Key questions.
Position. Do not adopt. Treat this as a rejected candidate with a useful reference implementation. The evaluation is still valuable because it surfaces a real gap — we have no consistent way to dark-launch, run controlled rollouts, or kill a bad release without a redeploy — and that gap costs engineering velocity and widens incident blast radius.
Stack fit. Poor as packaged; workable only as a conceptual reference. Laravel Pennant (first-party, Laravel 10.37+) covers release toggles and feature gating with a Feature::active() API, pluggable stores, and zero third-party maintenance burden. Where targeting, percentage rollouts with sticky bucketing, or cross-service consistency are in scope, an Unleash-compatible backend is the stronger option. The library's core idea — a named toggle resolved against a context — is sound and worth borrowing; the bundle wrapper is not.
Migration path. If legacy Symfony2 consumers exist, do not port the bundle. Apply a strangler pattern: define a narrow internal contract — ToggleResolver with isActive(string $flag, array $context): bool — implement it once over Pennant, and add a second adapter that proxies to the legacy Symfony2 service during cutover. Call sites depend on the contract, never on either implementation, so the legacy adapter is deleted when the last Symfony2 process retires. This also gives us an escape hatch if we later move to a managed platform: swap the adapter, leave call sites untouched.
Compatibility. Treat as a hard blocker pending verification. Confirm composer.json PHP and Symfony component constraints against our runtime (PHP 8.2+ for Laravel 11/12). Even if constraints happen to resolve, untyped PHP 5-era code will emit deprecations and will not pass static analysis at our quality gate. Verification is a two-hour task, not a spike — do it first, before any design work.
Sequencing.
Maintenance. A fork is a permanent, unbudgeted liability: no upstream commits, no security advisories, no compatibility patches as PHP and Laravel advance. Every future framework upgrade becomes a manual audit of code we own but did not write, and the cost recurs annually rather than once. Against zero adoption signal, this is a poor trade.
Support. No vendor, no community, no issue history to search. The only escalation path is an internal engineer reverse-engineering a seven-year-old bundle — an unpredictable and poorly bounded support burden. Contrast with Pennant, where the answer is in the Laravel documentation and the maintainer is the framework team.
Scaling. Toggle evaluation is in-process and cheap, but naive implementations hit the store on every check, turning hot paths into a database round-trip per request. Whatever backend is chosen must resolve the flag set once per request and cache it; Pennant's scoped stores handle this, and a hand-rolled fork would need the same built and tested from scratch. Cross-service consistency needs a plan too — a cached in-process store lags flag changes by the cache TTL, which is unacceptable for kill switches during an incident.
Failure modes.
Ramp-up. Low for anyone with Symfony experience, but the team is Laravel-oriented, so we would pay cognitive overhead to learn a foreign bundle convention for a capability the framework already exposes idiomatically. That overhead is recurring — paid on every onboarding and every new hire — not a one-time learning cost.
Recommended next step. Close this evaluation as a rejected candidate with a captured reference implementation. Spend a short spike sizing an in-house Pennant-based toggle service (roughly one engineer-day including tests) against a three-month Unleash trial, and decide the governance requirements — audit trail, targeting, sticky bucketing, cross-service consistency — first. Those requirements, not the library, determine the answer. Separately, capture the list of "what must we be able to turn off instantly?" as a standing PM-owned artefact; it is useful regardless of which backend we pick.
How can I help you explore Laravel packages today?