Feature flag — toggling features without code deployment
Intermediate5 min read·eng-18-010
interview
Concept
Feature flag (feature toggle) — a configuration switch that enables or disables a feature in production without deploying new code. Turn features on or off for all users, or selectively for specific users, groups, or percentages of traffic.
What feature flags enable:
- Dark launches: Deploy code to production but hide the feature. Enable for internal users first, then roll out.
- Gradual rollouts: Enable for 1% of users, monitor, then 10%, 50%, 100%.
- A/B testing: Enable feature variant A for 50% of users, variant B for 50%.
- Kill switch: Instantly disable a feature if it causes problems (no deploy needed).
- Beta access: Enable features for specific users or groups (beta testers, premium subscribers).
Trunk-based development: Feature flags allow developers to merge code to main daily (no long-lived feature branches) — the unfinished feature is just hidden behind a flag.
Types:
- Boolean: Feature is on or off.
- Percentage-based: On for X% of users.
- User-targeting: On for specific user IDs, emails, or roles.
- Scheduled: On between dates (e.g., a sale feature).
Tools: Laravel Pennant (official), GrowthBook, LaunchDarkly, Unleash, Flipper (Ruby, but popular reference).
Cleanup: Feature flags accumulate as technical debt. Once a feature is fully rolled out and stable, remove the flag and the old code path.
Code Example
php
<?php
// LARAVEL PENNANT — official feature flag package
// Install: composer require laravel/pennant
// Define features in AppServiceProvider::boot()
use Laravel\Pennant\Feature;
Feature::define('new-checkout', fn (User $user) => $user->isInBetaProgram());
Feature::define('ai-recommendations', function (User $user) {
// Gradual rollout: 10% of users
return $user->id % 10 === 0;
});
Feature::define('dark-mode', true); // enabled for everyone
// CHECK feature flags in controllers/views
class CheckoutController extends Controller
{
public function show(Request $request): View
{
if (Feature::active('new-checkout')) {
return view('checkout.v2');
}
return view('checkout.v1');
}
}
// In Blade views
@feature('new-checkout')
<x-checkout-v2 />
@else
<x-checkout-v1 />
@endfeature
// In API responses
return response()->json([
'features' => [
'new_checkout' => Feature::active('new-checkout'),
'ai_recs' => Feature::active('ai-recommendations'),
'dark_mode' => Feature::active('dark-mode'),
],
]);
// SEGMENT-BASED targeting
Feature::define('premium-analytics', function (User $user) {
return $user->subscription?->plan === 'premium';
});
// PERCENTAGE ROLLOUT
Feature::define('new-editor', function (User $user) {
return Feature::lottery(0.25); // 25% of users
});
// STORAGE — flags stored in DB (laravel_pennant table) or cache
// php artisan pennant:install
// php artisan migrate
// Enabling for specific users via artisan or admin panel:
Feature::activateForEveryone('dark-mode');
Feature::activate('new-checkout', $specificUser);
Feature::deactivate('new-checkout', $specificUser);