Managing Flag Debt
Why feature flags rot into technical debt, how to spot stale flags, and a repeatable process for cleaning them up before they cause an outage.
12 min read
The debt nobody budgets for
Feature flags are cheap to add and expensive to leave. Every flag you have created across the previous chapters - a progressive rollout here, an experiment there - was born temporary. The rollout finishes, the experiment concludes, the migration lands. But the flag rarely gets removed, because removing it is unglamorous work that ships no visible value. So it stays. Multiply that by a few hundred and you have flag debt: a codebase where nobody is quite sure which of the if flag.enabled branches still matter.
This is not a hypothetical annoyance. Stale flags cause real incidents. The most famous is the 2012 Knight Capital collapse, where an old flag was repurposed and a dormant code path came back to life, costing the firm around 440 million dollars in 45 minutes. You do not need a trading firm’s stakes to feel the pain. Every dead flag is a branch a new engineer must reason about, a line in a config nobody dares delete, and a switch someone can flip by accident.
The core insight is that a flag has a lifecycle, and most teams only build the first half of it. They are great at creating flags and terrible at retiring them. Managing flag debt means building the second half on purpose.
The lifecycle of a flag
Think of every flag as passing through stages:
- Created with a clear type, owner, and intended lifespan.
- Rolling out as you ramp exposure per the progressive delivery chapter.
- Fully served at a stable 100 percent or 0 percent, its decision made.
- Code removed so the winning branch becomes the only branch.
- Archived in the platform once no code references it.
Debt is what happens when flags stall between stage 3 and stage 4. The flag is decided, everyone knows the answer, but the cleanup never gets scheduled. The single most effective habit is treating stage 4 as part of the definition of done for the feature, not a someday task.
It helps enormously to distinguish flag types, because they have different lifespans. Release flags and experiment flags are temporary and should be removed within weeks. Operational flags like kill switches and long-lived permission or entitlement flags are meant to live indefinitely and should be excluded from cleanup sweeps. The feature flags best practices guide breaks these categories down further.
Spotting stale flags
You cannot clean up what you cannot see. Three signals reliably surface debt.
Age plus stable serving. A flag that has served 100 percent of traffic for thirty days is almost certainly a finished release flag. Most platforms expose creation date and rollout percentage, so this is a query you can run.
Last-evaluated timestamp. If the SDK has not evaluated a flag in weeks, either the code path is dead or the flag is unreachable. Both mean the flag is a candidate for removal. Watch for the trap here: a flag can still be referenced in code that simply is not being exercised, so confirm before deleting.
Naming and ownership. A flag called test-thing-2 with no owner is debt by definition, because nobody will ever feel responsible for removing it. This is why naming conventions matter so much. A scheme like release_checkout-redesign_2026q1 encodes type, purpose, and vintage, so a scan can find every Q1 release flag at once. The feature flag naming conventions post gives a full scheme worth stealing.
A repeatable cleanup process
Ad hoc cleanup does not scale. Turn it into a routine.
- Tag at creation. Every temporary flag gets an owner, a type, and a review date. If your platform supports tags or maintainer fields, use them.
- Run a monthly report. List flags past their review date, or serving one value stably for over thirty days, or unevaluated for two weeks. Sort by age.
- Confirm the served value. Check the flag is genuinely fully rolled out one direction, so removal changes nothing at runtime.
- Remove the code first. Delete the losing branch, keep the winning one, run the tests. The flag reference is now gone from the codebase.
- Archive the flag. Only after no code references it, retire the flag in the platform. Removing the config before the code is how you cause an outage, so always do it in this order.
Bake this into your rhythm - a recurring “flag cleanup” ticket each sprint clears a handful before the pile grows. The how to clean up feature flags walkthrough turns this into a concrete checklist.
How the real tools help
Platforms increasingly ship debt management, not just flag creation.
LaunchDarkly surfaces flag status and can flag “stale” flags that have served one variation for a long time, plus code references that show every place a flag is used so you know what to delete. That code-reference feature turns cleanup from guesswork into a targeted edit.
Unleash has an explicit flag-lifecycle model and reports potentially stale flags, which suits teams that want this discipline self-hosted and open source.
ConfigCat provides a Zombie Flags report that lists flags likely safe to retire based on age and evaluation activity, exactly the signals described above.
Flagsmith supports tagging and ownership metadata so you can build the tag-at-creation habit into a scan. For a broader operational view, the feature flag management guide covers governance across a whole organization.
Common mistakes
- Deleting config before code. Remove the flag in the platform while code still reads it and you get an undefined default, often a production incident. Code first, always.
- No owner. An unowned flag never gets cleaned, because responsibility is diffuse. Assign at creation.
- Treating cleanup as optional. If it is not in your definition of done or on a recurring schedule, it will not happen, and the pile only grows.
- Cleaning up kill switches. Not all flags are temporary. Exclude long-lived operational flags from your sweeps deliberately.
Key takeaways
- Flag debt is the accumulated cost of flags that outlived their purpose, and it causes real outages, not just clutter.
- Every flag has a lifecycle, and most teams only build the create half - managing debt means building the retire half.
- Surface stale flags by age with stable serving, last-evaluated time, and naming or ownership signals.
- Always remove referencing code before archiving the flag, and make cleanup a scheduled routine rather than a heroic project.
That completes the core of the course. You can now decouple deploy from release, ramp changes safely with progressive delivery, prove whether they worked with experiments, and retire the flags you created without leaving a minefield behind. Revisit any chapter from the Learn hub whenever you need a refresher.
Frequently Asked Questions
What is flag debt?
Flag debt is the accumulated cost of feature flags that have outlived their purpose but still sit in your code and configuration. Each stale flag adds a branch to reason about, a config to maintain, and a chance for someone to flip the wrong switch.
How do I know a flag is safe to remove?
A flag is safe to remove when its rollout is at a stable 100 percent or 0 percent, its purpose is resolved, and no other code path depends on it. Most platforms show last-evaluated timestamps so you can confirm a flag is fully served one way before deleting it.
Should every flag have an expiry date?
Temporary flags should. Release and experiment flags are meant to be short-lived, so tagging them with an owner and a review date makes cleanup a scheduled task rather than an archaeology project. Long-lived operational flags like kill switches are the exception.
Continue Learning
Newsletter
Get the Feature Flags Newsletter
Platform benchmarks, real pricing data and progressive delivery practice. No spam.
LaunchDarkly Review
Unleash Review
ConfigCat Review
Flagsmith Review