Feature Flag
A technique that lets teams enable or disable features at runtime without deploying new code, enabling gradual rollouts and A/B testing.
What Is a Feature Flag?
A feature flag (also called a feature toggle, feature switch, or feature gate) is a mechanism that allows development teams to enable or disable functionality in a running application without deploying new code. At its simplest, a feature flag is a conditional statement that checks a configuration value to determine whether a block of code should execute. At scale, feature flags become a sophisticated system for controlling who sees what, when, and under what conditions.
Feature flags decouple deployment from release. Code containing a new feature can be deployed to production behind a flag that is turned off. The feature is present in the codebase but invisible to users. When the team is ready — after internal testing, a marketing launch, or gradual rollout — the flag is turned on, and the feature becomes available. If problems arise, the flag is turned off instantly, without requiring a code rollback or new deployment.
The practice originated in the early 2000s and gained widespread adoption at companies like Flickr, Facebook, and Google, where deploying to millions of users required more control than a binary “deployed or not” offered. Today, feature flags are supported by dedicated platforms like LaunchDarkly, Split, Unleash, and open-source libraries available in every major programming language.
How It Works
A feature flag implementation consists of three components: the flag definition, the evaluation logic, and the management interface.
Here is a basic example in a web application:
// Feature flag evaluation in application code
import { featureFlags } from './flags-client';
async function renderDashboard(user: User) {
const dashboard = new Dashboard();
// Boolean flag — simple on/off
if (await featureFlags.isEnabled('new-analytics-widget', user)) {
dashboard.addWidget(new AnalyticsWidget());
}
// Percentage rollout — gradual release
if (await featureFlags.isEnabled('redesigned-nav', user)) {
dashboard.useNavigation(new RedesignedNav());
} else {
dashboard.useNavigation(new ClassicNav());
}
// Variant flag — A/B testing
const checkoutVariant = await featureFlags.getVariant('checkout-flow', user);
if (checkoutVariant === 'streamlined') {
dashboard.setCheckout(new StreamlinedCheckout());
} else {
dashboard.setCheckout(new StandardCheckout());
}
return dashboard.render();
}
And a corresponding flag configuration:
{
"flags": {
"new-analytics-widget": {
"enabled": true,
"rules": [
{ "attribute": "team", "value": "internal", "enabled": true },
{ "attribute": "percentage", "value": 0, "enabled": false }
]
},
"redesigned-nav": {
"enabled": true,
"rules": [
{ "attribute": "percentage", "value": 25 }
]
},
"checkout-flow": {
"enabled": true,
"variants": ["standard", "streamlined"],
"distribution": [50, 50]
}
}
}
Feature flags can operate at several levels of sophistication:
- Boolean flags — Simple on/off toggles that enable or disable a feature for everyone.
- User-targeted flags — Flags that are enabled for specific users, teams, or accounts.
- Percentage rollouts — Flags that enable a feature for a configurable percentage of traffic.
- Variant flags — Flags that assign users to different variants of a feature for A/B testing.
The flag evaluation typically happens at runtime, with the application checking a remote configuration service or a locally cached configuration. This allows flags to be changed without restarting the application — a key advantage over environment variables or compile-time configuration.
Why It Matters
Feature flags are a critical enabler of continuous deployment. They solve the fundamental tension between “deploy frequently” and “release carefully.” Without feature flags, deploying code to production is synonymous with exposing it to users. With feature flags, these are independent actions. Code can be deployed continuously while features are released on a controlled schedule.
This separation provides several concrete benefits. Product teams can coordinate feature launches with marketing campaigns without being constrained by deployment schedules. Engineers can merge incomplete features behind flags, avoiding long-lived feature branches that accumulate merge conflicts. On-call teams can disable a problematic feature in seconds rather than waiting for a code fix to be built, tested, and deployed.
Feature flags also enable data-driven product development through A/B testing. By showing different variants of a feature to different user segments and measuring outcomes, teams can make product decisions based on evidence rather than opinion. Companies like Netflix and Booking.com run thousands of concurrent experiments using feature flag infrastructure.
Best Practices
-
Establish a flag lifecycle. Every feature flag should have an owner, a purpose, and an expiration date. Temporary flags used for rollouts should be removed once the feature is fully launched. Permanent flags (like kill switches) should be documented and reviewed periodically.
-
Keep flag evaluation fast. Feature flags are evaluated on every request, often multiple times. Use local caching with background refresh to ensure flag evaluation adds negligible latency. Avoid synchronous network calls on the critical path.
-
Test both flag states. Ensure your test suite validates application behavior with each flag both enabled and disabled. A flag that works when enabled but crashes the application when disabled is a liability, not a safety mechanism.
-
Use flags for operational safety. Beyond feature rollouts, use kill-switch flags for expensive operations, external service calls, and resource-intensive features. When a downstream service is overloaded, a kill switch lets you disable non-critical calls instantly.
-
Centralize flag management. Use a dedicated feature flag platform rather than scattering flag logic across configuration files, environment variables, and database tables. Centralization provides visibility into which flags exist, who owns them, and what state they are in.
Common Mistakes
-
Accumulating stale flags. Feature flags that are never cleaned up create technical debt. Each flag adds a conditional code path that increases complexity and testing surface area. A codebase with hundreds of stale flags becomes difficult to reason about. Schedule regular cleanup sprints to remove flags for features that have been fully launched.
-
Nesting flags deeply. Code that checks multiple flags in nested conditions becomes extremely difficult to understand and test. If feature A is enabled and flag B is on but only for users in segment C, the combinatorial complexity explodes. Keep flag logic simple and avoid deeply nested flag conditions.
-
Using flags as a substitute for proper testing. Feature flags are a release mechanism, not a testing mechanism. A feature that is deployed behind a flag but never tested in a production-like environment will still fail when the flag is turned on. Test thoroughly before toggling flags.
Related Terms
Learn More
Tool Reviews
Free Newsletter
Stay ahead with AI dev tools
Weekly insights on AI code review, static analysis, and developer productivity. No spam, unsubscribe anytime.
Join developers getting weekly AI tool insights.
Amazon Q Developer
Augment Code
Bito AI
Claude Code