Feature Toggle Types
debt(d7/e5/b7/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints flag automated=no, and while tools like unleash, launchdarkly, flagsmith, and laravel-pennant can manage flags, they do not automatically detect misclassified toggle types or flag lifecycle violations. Flags accumulating indefinitely or being treated uniformly only becomes visible through deliberate code review or an explicit flag inventory audit — not through automated tooling.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix is conceptually simple (match toggle type to lifecycle), but the common_mistakes reveal that flags are often scattered deep in domain logic, lack ownership, and have accumulated over time. Properly reclassifying, adding lifecycle policies, and cleaning up stale flags touches multiple files and requires coordinated effort across the codebase, though it stops short of a full architectural rework.
Closest to 'strong gravitational pull' (b7). Feature flags that are mismanaged accumulate as flag debt across web, api, and cli contexts (per applies_to). Every new feature, deployment decision, and A/B test is shaped by the existing flag strategy. Flags hardcoded deep in domain logic create a persistent drag on every change — developers must understand which flags are active, safe to remove, or permanent circuit breakers before modifying any flag-guarded code path.
Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception field directly states the trap: developers assume all feature flags are the same and manage them identically. This contradicts the reality that release toggles (short-lived), ops toggles (permanent), experiment toggles (time-boxed), and permission toggles (per-user) have fundamentally different lifecycles and removal policies. A competent developer familiar with basic feature flags will routinely apply the wrong lifecycle policy, causing flag debt or premature removal of critical circuit breakers.
Also Known As
TL;DR
Explanation
Pete Hodgent's taxonomy: Release Toggles gate incomplete features for trunk-based development — short-lived (days to weeks), removed once released. Ops Toggles control operational behaviour (kill switch for a feature under load) — potentially long-lived, owned by ops. Experiment Toggles (A/B tests) route cohorts to different code paths — medium lifetime, data-driven removal. Permission Toggles give specific users/tenants access to premium features — long-lived, permanent in the codebase. Each type has different implications: release toggles create technical debt if not cleaned up; experiment toggles require statistical significance before decision; permission toggles need admin UI. PHP libraries: flagsmith/flagsmith-php-client, unleash/client, or a simple database-backed implementation.
Diagram
flowchart TD
subgraph Release_Toggle
RT[Hide incomplete feature<br/>until ready to ship]
end
subgraph Experiment_Toggle
ET[A/B test - 50 pct see new UI<br/>50 pct see old UI]
end
subgraph Ops_Toggle
OT[Kill switch for heavy feature<br/>during incidents]
end
subgraph Permission_Toggle
PT[Beta users see feature<br/>before general release]
end
CONFIG[(Feature Flag Config)] --- RT & ET & OT & PT
style CONFIG fill:#6e40c9,color:#fff
style RT fill:#1f6feb,color:#fff
style ET fill:#238636,color:#fff
style OT fill:#f85149,color:#fff
style PT fill:#d29922,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Treating all feature flags the same — release flags should be removed after launch; ops flags should not.
- No flag inventory or ownership — flags accumulate with no one knowing if they are safe to remove.
- Toggling features mid-transaction — partial feature activation can leave data in inconsistent states.
- Hard-coding toggle checks deep in domain logic instead of at the entry point — toggles belong at boundaries.
Code Examples
// Feature flag with no expiry or owner — permanent flag debt:
if (config('features.new_checkout')) {
// 'Temporary' flag from 18 months ago — never removed
// No one knows if false branch is still tested
// No ticket, no owner, no removal plan
}
// Release toggle — hide incomplete feature from users
$flags->isEnabled('new_billing_ui', $user);
// Experiment toggle — A/B test
$variant = $flags->getVariant('checkout_flow', $user); // 'control' or 'treatment'
// Ops toggle — kill switch for a live feature under load
if (!$flags->isEnabled('recommendation_engine')) {
return []; // disable when it's hammering the DB
}
// Permission toggle — role-based feature access
if ($flags->isEnabled('beta_dashboard', $user)) { ... } // only for beta users
// Implementation approaches:
// 1. Config file / env var — simplest, needs deploy to change
// 2. Database row — live changes, no deploy
// 3. Feature flag service (LaunchDarkly, Flagsmith, Unleash) — targeting rules