Building a feature-flag discipline that survives contact with reality
Feature flags are the single most underrated investment in shipping software safely. They are also the easiest engineering practice to lose control of. We have walked into codebases with hundreds of dead flags, mutually contradictory flags, and flags that nobody on the team can explain.
The discipline that prevents this is not complicated, but it has to be applied early and consistently.
Classify your flags
There are four kinds of flags, and confusing them is the root cause of most flag debt.
Release flags decouple deploy from release. They have a lifespan measured in days or weeks and they are deleted the moment the feature is fully rolled out.
Experiment flags drive A/B tests. They have a defined evaluation period and are removed as soon as the experiment reports.
Operational flags control runtime behavior — circuit breakers, kill switches, gradual rollouts of infrastructure changes. These can live for years, but they should be small in number and owned by a platform team.
Permission flags gate features by customer or tier. These belong in your billing system or your RBAC model, not in your feature flag tool.
The discipline
Every flag has an owner, a class, and an expiry date in the flag system itself. A weekly automated report surfaces flags past their expiry and assigns them to the owner. Removing a flag is a normal pull request, not a special event.
Code that reads a flag is wrapped in a thin, typed interface so that removing the flag is a refactor, not a manual code review. Default values are explicit, written down, and tested.
The thing nobody warns you about
Flags interact. A user can be in a combination of flag states that nobody designed for. The fix is to keep release flags binary, keep their lifespan short, and resist the temptation to nest. If you need to express a real product permission, do it with a real permission, not a stack of flags.
Get this discipline in place when you have ten flags. By the time you have a hundred, it will be too late.