laravel/pennant
Laravel Pennant is a simple, lightweight feature flag library for Laravel. Define flags in a service provider and check them with Feature::active() to roll out features gradually to users, segments, or percentages of traffic.
Architecture fit
Feature facade/contract. It slots into the existing provider + facade conventions rather than introducing a parallel configuration or runtime model.Feature name, evaluated against a scope (a model instance, or the global scope added in 1.26.0). Drivers (database, array, null, and custom) supply persistence and resolution.EnsureFeaturesAreActive, including all checks added in 1.5.0), Blade directives (@feature, @featureany), events for feature updates, a pennant:purge command with exclusions, before hooks (1.9.0/1.14.0), a nameMap decorator for renaming, PHP enum support, and external-driver hooks for retrieving defined features per scope.Integration feasibility
composer require laravel/pennant plus a published migration for the database driver. No external SaaS, API keys, network calls, or vendor onboarding — this is the lowest-friction integration class available.array driver means flags do not require a database in the test suite, which keeps CI parity intact.Technical risk
activate/deactivate/forget), but "flip a rule for 10% of EU users without a release" is not a native capability. If product stakeholders expect a LaunchDarkly-style dashboard, scope expectations now.Lottery-based closure re-rolls per request, producing a flickering experience unless the result is persisted per scope or derived from a stable hash. This is the most common implementation defect and needs an internal pattern, not ad-hoc code.pennant:purge cleans stored values, not dead definitions or dead code branches. Stale flags are the dominant long-term cost.Key questions
User model, tenant, or global? Multi-tenancy changes the row-cardinality and purge strategy materially.^1.x and tracking Laravel's release cadence, or pinning?Stack fit
Migration path
Feature per existing boolean, wrap the existing check site in Feature::active(...), and delete the config key. Call sites change once; behaviour is unchanged on day one.Feature::active() as the single call-site API. This decouples the eventual cutover from the code change and is the recommended path if a provider contract is in force.array driver in tests and a single internal-only flag, then publish the migration and move to the database driver.Compatibility
nameMap decorator, 1.18.0). PHP 8.4/8.5 and Laravel 13 support mean the package is not a constraint on the platform upgrade roadmap.Sequencing
array driver in tests.database driver.if statements in controllers.pennant:purge schedule with an exclusion list for long-lived flags.Maintenance
^1.x; releases are frequent but small and mostly additive, so upgrade cost is near zero.Dependents: 0 is a weak third-party adoption signal in this dataset (plausibly a reporting artifact for a first-party package). Treat the confidence case as "maintained by the Laravel core team," not "battle-tested across hundreds of public dependents."Support
Scaling
loadAll (1.10.0) and per-scope bulk retrieval keep page rendering from issuing N flag queries.Failure modes
before hook that short-circuits — before this happens in production, not during an incident.nameMap and treat renames as migrations.Ramp-up
How can I help you explore Laravel packages today?