Laravel Pennant: Feature Flags
Laravel Pennant: Feature Flags
Laravel Pennant: Feature Flags
Tip: Define Feature
Feature::define('new-dashboard', fn(User $user) => $user->isAdmin());
Gotcha: Feature Check
if (Feature::active('new-dashboard')) {
// Show new dashboard
}
Tip: Feature for Specific Users
Feature::forUser($user)->active('new-dashboard');
Gotcha: Feature in Blade
@feature('new-dashboard')
<x-new-dashboard />
@else
<x-old-dashboard />
@endfeature
Tip: Stored Features
'driver' => 'database',
Persist feature flags in the database for per-user control.
Gotcha: Feature Resolution
Features are resolved per-request. Changing a feature mid-request doesn't affect already-resolved checks.
Tip: Use route:cache Carefully
php artisan route:cache is fast, but it doesn't work with closure-based routes. Every time you cache routes, Laravel serializes them. If you have Route::redirect() or closure callbacks, the cache breaks. Stick to controller-based routes in production.
Tip: Model APP_KEY Rotation
Rotating APP_KEY invalidates all encrypted data — cookies, encrypted DB columns, and password reset tokens. If you must rotate (e.g., after a leak), plan a migration that re-encrypts existing data with the new key.
Gotcha: Local Scope Leaks
Global scopes defined in booted() apply to ALL queries on that model — including relationships. An innocent User::all() in admin panel might exclude soft-deleted users if a global scope is active.
Senior Insight
Feature flags are essential for continuous deployment, but they introduce complexity that most teams underestimate. I've seen flags accumulate over months, with dead code paths that nobody remembers how to remove. My practice: pair every feature flag with a cleanup ticket created at the same time, assigned to the same developer. When the flag is enabled in production, the cleanup ticket should be in the next sprint.
Source: Laravel News (https://laravel-news.com/), Freek.dev (https://freek.dev/tags/laravel), Spatie Blog (https://spatie.be/blog)