A Feature Flag Is a Production Change That Skips Your Deploy Pipeline

Two costs land the moment you add a flag, and neither is visible that day. It creates a branch in your code that nothing will ever make you delete, and it lets someone change production behaviour without passing through any of the safety machinery you built for changing production behaviour.

Tech Talk News Editorial9 min read
ShareXLinkedInRedditEmail
A Feature Flag Is a Production Change That Skips Your Deploy Pipeline

Key takeaways

  • Feature flag technical debt is the accumulated cost of conditional logic that remains in the codebase after it is no longer needed, and every toggle adds a code path that needs testing, monitoring and eventual removal.
  • Each boolean flag doubles the number of theoretical states, so ten flags describe 1,024 combinations while a test suite realistically exercises two of them, meaning the configuration running in production may never have been tested as a whole.
  • Flipping a flag changes production behaviour without a deploy, which routes the change around code review, continuous integration, canary rollout and deploy-based rollback.
  • Flag tooling now models a lifecycle explicitly, with states such as active, potentially stale and stale, and platforms will mark a flag potentially stale automatically once it passes its expected lifetime.
  • The practices that work are assigning every flag a named owner, giving temporary flags mandatory expiration dates, and putting removal into the definition of done rather than leaving it to a future cleanup.
  • Automated codemods connected to lifecycle webhooks have replaced manual audits as the baseline for removal, with Uber's Piranha scanning source code to detect and delete stale flag logic.

Feature flags are genuinely good. They separate deploying code from releasing behaviour, which lets you ship continuously, roll out gradually, and turn something off without a rollback. Nothing below argues against using them.

But two costs arrive the moment you add one, and neither is visible on the day you do it.

2^n
Theoretical states from n boolean flags
1,024
Combinations from ten flags
~2
Combinations your test suite actually runs
No deploy
What a flag flip requires

Cost One: The Test Matrix Multiplies

Every boolean toggle creates another divergent pathway through your code.[1] Not an addition, a doubling: n flags describe 2n theoretical states.

Ten flags is 1,024 combinations. Your test suite probably runs two of them, all-on and all-off, and possibly only one. Which means the specific combination of flag values running in production right now has, with high probability, never been executed as a whole by anything.

This is not a hypothetical bug class. It is where the ones that survive to production live: two features that each work, and are each tested, and interact badly only when both are enabled for the same user. Nothing in your pipeline was ever asked that question.

Flags do not add code paths. They multiply them. Ten booleans is a thousand configurations and a test suite that has seen two.

Cost Two: It Routes Around Your Safety Machinery

This is the one I think is genuinely under-said, and it follows from the thing flags are praised for.

Consider what you built around deploys. Code review. Continuous integration. A canary or staged rollout. Rollback by reverting a commit. An audit trail of who changed what and when. All of that exists because changing production behaviour is dangerous and you wanted controls on it.

Now: flipping a flag changes production behaviour and passes through none of it. The code was reviewed, months ago, possibly by people who have left. The decision to expose that code to real users happens in a dashboard, often instantly, often globally, frequently by someone who is not on the team that wrote it.

A flag flip has the blast radius of a deploy and the ceremony of a setting. That asymmetry is the entire point of flags and also their largest unmanaged risk, and most organisations have never written it down.

Why this matters

The practical fix is not to remove the capability, it is to give flag changes the controls deploys already have. Audit who flipped what. Require a second approver on flags that gate anything financial or customer-facing. Stage the rollout by percentage rather than going global. And make flag changes visible in the same place deploys are, so an incident timeline shows both. Most incident reviews that stall on “nothing was deployed” end when someone finally checks the flag log.

Why Flags Never Get Removed

Flag debt is the accumulated cost of conditional logic that stays after it is no longer needed.[1] Everyone knows they should delete old flags. Almost nobody does, and the reason is structural rather than lazy.

Removal has no deadline, produces no visible feature, carries a small non-zero risk of breaking something, and requires knowing whether the flag is genuinely finished. That last part is the killer: six months on, nobody is certain whether a flag is a completed rollout or load-bearing configuration, and the safe-feeling choice is always to leave it.

So flags accumulate, and the code grows conditionals whose purpose nobody remembers, which is a specific and unusually annoying flavour of developer experience decay: every subsequent reader must decide whether each branch matters.

What Actually Works

Model the lifecycle explicitly. Tooling now does this, with states like active, potentially stale, and stale, and platforms will mark a flag potentially stale automatically once it passes its expected lifetime.[2]That single mechanism converts “is this finished?” from an archaeology problem into a query.

Set an expiry when you create it. Mandatory expiration dates on temporary flags, decided while you still remember the intent.[1] The cost of writing a date is seconds; the cost of reconstructing that judgement in six months is an afternoon and a wrong guess.

Give every flag an owner. A named person, not a team.[1] Unowned flags are exactly the ones that survive forever, because nobody has standing to delete them.

Put removal in the definition of done. A rollout is not complete when the flag reaches 100%, it is complete when the flag is gone.[1] Otherwise removal is a backlog item competing with features, and it loses every time.

Automate the deletion.Codemods connected to lifecycle webhooks are now the baseline rather than manual audits, and Uber's Piranha scans source code to detect and delete stale flag logic mechanically.[3]Worth knowing this class of tool exists, because “delete the branch and its tests correctly” is exactly the kind of mechanical edit a human does slowly and inconsistently.

Distinguish temporary from permanent. Some toggles are legitimately forever: kill switches, regional configuration, plan entitlements. Label those, so they are not mistaken for cleanup somebody skipped, and so the stale-flag report stays credible enough that people act on it.

The One Thing To Do If You Do Nothing Else

Emit the evaluated flag state on every request, alongside the build ID.

Without it, “why did this user see different behaviour?” has no answer available to you, because the code was identical and only the evaluation differed. With it, that question is a filter. This is the same argument as high-cardinality observability, and flag state is one of the two fields most teams omit and most need.

Takeaway

Flags are worth their cost, but the cost is real and arrives immediately. Each one doubles your state space, so production is running a combination nothing has tested. And a flag flip has a deploy's blast radius with a setting's ceremony, bypassing the review, CI, canary and rollback machinery you built precisely for changes of that size. Set an expiry and an owner at creation, treat a rollout as unfinished until the flag is deleted, automate the deletion, and put evaluated flag state on every request so you can answer the question flags create.

Sources and further reading

  1. 1.Reporting"The complete guide to managing feature flag technical debt". Source for the definition of flag debt, the multiplying test matrix, and the practices of named owners, mandatory expiry dates and removal inside the definition of done.
  2. 2.PrimaryUnleash documentation, "Managing feature flag technical debt". Source for the active, potentially stale and stale lifecycle states and automatic marking once a flag passes its expected lifetime.
  3. 3.ReportingLaunchDarkly, "Reducing technical debt from feature flags". Source for automated codemods connected to lifecycle webhooks as the baseline for removal, and for Uber's Piranha detecting and deleting stale flag logic.

Frequently asked questions

What is feature flag technical debt?
It is the accumulated cost of conditional logic that stays in your codebase after the flag has served its purpose. Every toggle creates a code path that must be tested, monitored and eventually removed, and debt accrues when the removal never happens because nothing forces it.
Why are feature flags hard to test?
Because each boolean flag doubles the number of possible states. Ten flags describe 1,024 combinations, and no realistic test suite covers more than a couple of them, so the specific combination running in production has quite likely never been exercised as a whole. Flags do not add paths linearly, they multiply them.
Do feature flags bypass code review?
Effectively yes, for the change in behaviour. The code was reviewed, but the decision to enable it for real users usually happens in a dashboard rather than in a pull request, so it skips review, continuous integration, canary rollout and the ability to roll back by reverting a deploy. That is the same power a deploy has, without the same controls.
How long should a feature flag live?
A temporary flag should have an explicit expiration date set when it is created, and tooling now supports this directly by marking a flag potentially stale automatically once it passes its expected lifetime. Permanent operational toggles are a different category and should be labelled as such so they are not mistaken for cleanup that never happened.
How do you clean up stale feature flags?
Automated codemods have replaced manual audits as the baseline, with Uber's Piranha scanning source code to detect and delete stale flag logic mechanically. The organisational half matters as much: every flag needs a named owner and removal has to sit inside the definition of done rather than in a backlog item nobody prioritises.
Should you record feature flag state in your logs?
Yes, and it is one of the highest-value fields to attach to every request. Without it you cannot answer why one cohort of users saw different behaviour, because the code was identical and only the flag evaluation differed, which makes the flag state the explanation and its absence a dead end.

Written by

Tech Talk News Editorial

Computer engineering background. Writes about software, AI, markets, and real estate, and the places where the three meet.

More about the author
ShareXLinkedInRedditEmail