Feature Flag / Feature Toggle
debt(d9/e7/b7/t5)
Closest to 'silent in production until users hit it' (d9). The detection_hints specify automated=no and tools are feature-flag management platforms (Unleash, LaunchDarkly, Flagsmith) that help manage flags but do not automatically detect misuse patterns like flag debt accumulation, nested flag conditions, or missing cleanup. The code_pattern describes 'new feature deployed to all users at once with no gradual rollout or kill switch' — this is invisible at compile time, lint time, and even in testing; it only manifests as a missing safety mechanism in production. Flag accumulation and dead-code conditions are silent until someone is tracing a production bug.
Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix describes the happy-path of wrapping a feature and decommissioning old code, but the common_mistakes enumerate the real remediation cost: cleaning up accumulated flag debt means locating every flag check across the codebase, removing the conditional branches, deleting the old code paths, and updating tests — a cross-cutting operation. Nested flag conditions that create combinatorial test space make this significantly harder than a localised fix.
Closest to 'strong gravitational pull' (b7). Feature flags apply across web, api, and cli contexts and are tagged as deployment/devops/continuous-delivery patterns, meaning they affect every deployment pipeline and release decision. The common_mistakes highlight that unremoved flags become permanent dead code conditions that shape every future change to the affected code paths. Flag debt accumulates across the whole codebase over time, imposing a persistent productivity tax on all work streams touching flagged areas.
Closest to 'notable trap — a documented gotcha most devs eventually learn' (t5). The misconception field explicitly states that developers believe flags are only for hiding incomplete features, missing the broader uses (A/B testing, canary releases, kill switches). The common_mistakes reinforce the cleanup trap: most developers deploy flags without planning removal, leading to flag debt. These are documented, well-known gotchas that most teams encounter and learn — serious enough to cause real pain but not contradicting an analogous concept in a catastrophic way.
Also Known As
TL;DR
Explanation
Feature flags (toggles) wrap new code in conditional blocks controlled by configuration, environment variables, or a remote flag service. They enable: trunk-based development (merge incomplete code safely), canary releases (enable for a percentage of users), A/B testing, kill switches for problematic features, and operational flags for performance tuning. The cost is codebase complexity — old flags must be cleaned up once permanently enabled/disabled. Organise flags by type (release, ops, experiment, permission) and define explicit removal criteria.
Common Misconception
Why It Matters
Common Mistakes
- Not cleaning up flags after the feature is fully released — flag debt accumulates and the conditions become permanent dead code.
- Using feature flags for configuration or environment differences — that is what environment variables are for.
- Nested feature flags that create combinatorial conditions impossible to test exhaustively.
- Not logging or monitoring flag state — when something breaks you can't tell which flag combination caused it.
Avoid When
- Flags are never removed — accumulated dead flags become permanent complexity and technical debt.
- The flag controls security-critical behaviour — a misconfigured flag disabling auth is catastrophic.
- Flags are used as permanent configuration instead of short-lived release toggles.
- Too many flags interact — combinatorial testing of N flags requires 2^N test cases.
When To Use
- Trunk-based development where incomplete features must be merged to main without being user-visible.
- Canary releases and A/B tests where the new behaviour is shown to a percentage of users.
- Kill switches for risky features that may need to be disabled instantly in production.
- Per-tenant or per-customer feature enablement in SaaS applications.
Code Examples
// Nested flags create untestable combinations:
if (featureEnabled('new_checkout')) {
if (featureEnabled('new_payment')) {
if (featureEnabled('new_tax_engine')) {
// 8 combinations to test — combinatorial explosion
}
}
}
class FeatureFlags {
public function isEnabled(string \$flag, ?User \$user = null): bool {
\$feature = Feature::where('key', \$flag)->first();
if (!\$feature || !\$feature->enabled) return false;
// Percentage rollout — hash user ID into 0-99 bucket
if (\$user && \$feature->rollout_percent < 100) {
\$bucket = crc32(\$flag . \$user->id) % 100;
return \$bucket < \$feature->rollout_percent;
}
return true;
}
}
if (\$flags->isEnabled('new_checkout', \$user)) {
return \$this->newCheckout->process(\$cart);
}
return \$this->legacyCheckout->process(\$cart);