IT Industry · Jul 17, 2026
Feature Flags Are Technical Debt With a Snooze Button
By OAR Team · 4 min read
IT Industry · Jul 17, 2026
By OAR Team · 4 min read
Feature flags solve a real problem: they let a team ship code to production without shipping the feature to users, decouple deploy from release, and give on-call a kill switch when something goes wrong at 2 a.m. Almost every team that adopts them becomes a permanent believer within a quarter. What fewer teams plan for is what happens to a flag after the decision it was created for has already been made.
A flag is created to answer a specific question: does this checkout redesign convert better, does this new query path hold up under load, is this integration safe to expose to a subset of customers. Once that question is answered — usually within weeks — the flag has no reason to exist. The feature is either fully rolled out or fully rolled back. In practice, the flag stays.
It stays because removing it requires someone to go back into code nobody’s actively working in, trace every place the conditional is checked, confirm none of the “off” paths are secretly still load-bearing, and ship a cleanup change that has no visible benefit to anyone outside the team. Compare that cost to the cost of doing nothing: zero. Every sprint, cleanup loses that comparison.
A codebase with thirty stale flags isn’t thirty times harder to reason about than one with a single stale flag — it’s worse than that, because flags interact. A user’s actual code path is determined by the combination of every flag that touches their request, and most flag systems don’t make that combination visible anywhere. Two flags that were each tested in isolation can produce a state nobody tested, because nobody realized both would ever be on for the same account at once. The bug that results from that combination doesn’t look like a flag problem when it’s reported — it looks like a mystery.
A flag guarding an incomplete or deprecated code path doesn’t just add clutter — it keeps that path reachable. Old authentication logic, a legacy API version, a permissive default that was supposed to be temporary: if the flag that hides it is still evaluated at runtime, the code is still live, and a misconfigured flag or an unexpected default can flip it back on for real traffic. Audits that focus on what’s deployed and skip what’s merged-but-flagged-off miss exactly this class of risk.
The fix isn’t fewer flags — flags are worth the operational safety they buy. The fix is treating each one as a loan with a maturity date rather than a permanent fixture. That means setting an expiration or a review date at creation time, not after the fact; assigning an owner who is accountable for the removal, not just the rollout; and tracking flag age as a first-class metric the way a team already tracks build time or test flakiness. Some teams add a CI check that fails a build when a flag crosses an age threshold without a linked removal ticket — a blunt tool, but an effective one, because it moves cleanup from “whenever someone has time” to “whenever CI insists.”
None of this requires new tooling most teams don’t already have. It requires treating flag removal as part of the feature, not as a separate, always-deprioritized task — because the flag that made a risky release safe is, from the day the decision is made, the next piece of debt on the books.
Filed under: IT Industry
IT Industry
Shipping a v2 endpoint is easy. The hard part is that every external caller now expects v1 to keep working, forever, on someone else's schedule.
IT Industry
Cloud bills keep surprising finance teams because the decisions that drive them are made by engineers, one merged PR at a time.
IT Industry
Writing the ALTER TABLE statement is the easy part — the real difficulty is getting every service and deploy in sync before and after it runs.