On this page
Feature Flags vs Feature Toggles: What's the Difference?
Feature flag and feature toggle are often used interchangeably, but flags are for release management and toggles are for runtime behavior. Learn the distinction, the four types, and how to use them without creating tech debt.
Quick answer
- Feature flags control who sees a feature during rollout (release management).
- Feature toggles control whether a feature is active in production (runtime behavior).
- In practice the terms are interchangeable, but knowing the four types helps you decide whether a flag should live for days or years.
The distinction (that most people ignore)
In practice, “feature flag” and “feature toggle” mean the same thing: an if statement that decides whether code runs. But the original distinction is useful:
| Feature Flag | Feature Toggle | |
|---|---|---|
| Purpose | Release management | Runtime behavior |
| Lifetime | Days to weeks | Hours to permanent |
| Changes | Flips once (off → on) | Flips repeatedly |
| Who changes it | Product manager, during rollout | Ops engineer, during incidents |
| Example | “Show new checkout to 10% of users” | “Disable payment retries during Stripe outage” |
The industry uses “feature flag” as the umbrella term. Pete Hodgson’s classic article names four types — and knowing them is more useful than knowing the flag/toggle distinction.
The four types of feature flags
1. Release flags
What they do: Hide unfinished code so you can deploy to production before the feature is ready. Ship dark, enable later.
if feature_flag("new-checkout-v2"):
return new_checkout()
else:
return old_checkout()Lifetime: Short. Remove within 1-2 weeks of the feature proving stable.
Example: You’re building a new checkout flow. You ship it behind a flag, QA tests it in production, and when it’s ready you flip the flag. Once stable, you delete the old code and the flag.
2. Experiment flags (A/B tests)
What they do: Route different users to different implementations and measure the outcome.
if experiment("checkout-button-color", user.id) == "green":
return green_button()
else:
return blue_button()Lifetime: Days to weeks — the duration of the experiment.
Example: You want to know which button color generates more conversions. The flag routes 50% to green, 50% to blue, and you measure the result. Once the experiment concludes, the losing variant and the flag are removed.
3. Ops flags (kill switches)
What they do: Let you disable a feature instantly in production without deploying code.
if ops_toggle("payment-retries"):
retry_payment(order)
# Operator flips this off during a Stripe outage to stop retry stormsLifetime: Long-term/indefinite. These are safety valves you hope never to use.
Example: During a third-party outage, payment retries are failing and building backpressure. You flip the kill switch to disable retries, letting the rest of the system function. When the outage resolves, you flip it back.
4. Permission flags
What they do: Gate features based on user tier, plan, or role.
if permission_flag("advanced-analytics", user.plan):
return analytics_dashboard()Lifetime: Permanent — tied to the business model.
Example: Premium users get advanced analytics. The flag checks the user’s plan, not a rollout percentage. These are essentially authorization checks with flag infrastructure.
When to use each type
| Type | Use when | Remove when |
|---|---|---|
| Release | Shipping unfinished code to production | Feature is stable (1-2 weeks) |
| Experiment | A/B testing | Experiment concludes |
| Ops | Need a kill switch for risky integrations | The risk is mitigated (or never — it’s a safety valve) |
| Permission | Feature gated by plan/role | The pricing model changes |
How AI assistants get this wrong
AI coding assistants default to the simplest pattern — an if statement with no cleanup plan:
# What AI generates:
if feature_flag("new-feature"):
new_feature()
# What it should consider:
if release_flag("new-feature", user.id, rollout_pct=10):
new_feature()
# ↑ has a rollout percentage, an owner, and a removal dateThe assistant doesn’t:
- Set a rollout percentage (it’s all-or-nothing)
- Add an owner or removal date
- Distinguish between a kill switch (keep) and a release flag (remove)
- Consider flag debt: every flag is an untested code path that makes testing combinatorially harder
Flag debt is real debt
Every feature flag doubles the number of code paths:
- 1 flag = 2 paths (flag on / flag off)
- 5 flags = 32 paths
- 10 flags = 1,024 paths
You cannot test all of them. That’s why release flags and experiment flags must be removed quickly — they’re temporary scaffolding, not permanent architecture. Ops flags and permission flags earn their keep by serving ongoing business needs.
Where this bites vibecoders
AI assistants add
if feature_flag(...)around every new feature without considering type or lifetime. Six months later, the codebase has 40 flags, half of them permanentlytrue, and nobody knows which ones are safe to delete. The fix: categorize every flag by type when you add it, and set a removal date for release and experiment flags.
Checklist
- Categorize every flag by type (release, experiment, ops, permission)
- Set a rollout percentage (never 100% on day one for release flags)
- Assign an owner and removal date to every release and experiment flag
- Kill switches default to ON — the code runs unless the toggle is flipped
- Review active flags monthly and remove any that are permanently ON
- Never reuse a flag name for a different purpose — create a new flag
FAQ
Are feature flags and feature toggles the same thing?
In practice, people use them interchangeably. The distinction: feature flags are about release management (controlling who sees what), while feature toggles are about runtime behavior (turning things on/off in production). A flag might stay for days; a toggle might flip back and forth in seconds.
When does a feature flag become technical debt?
When it outlives its purpose. A release flag should be removed within weeks of the feature proving stable. An ops kill switch might stay permanently. The rule: every flag should have an owner and an expected removal date. Flags without a removal plan accumulate and make the codebase unmaintainable.
What tools should I use?
For a small project, environment variables or a config file are enough. For a team, use a dedicated service: LaunchDarkly, Flagsmith (open-source), or Unleash (open-source). These give you gradual rollouts, A/B testing, and audit logs that if os.getenv(...) doesn’t.
Related topics
- What Is a Feature Flag?
- What Is Zero-Downtime Deployment?
- Rolling vs Blue-Green vs Canary Deployments: Which Should You Pick?
- What Is CI/CD?