Feature flag cleanup checklist
Every flag has an owner and a kill date — or it becomes the outage you shipped in advance.
A feature flag starts as safety and decays into debt. Each one is a second code path that only compiles in your head: a branch nobody reads, a config value nobody dares touch, an “off” state nobody has tested since the quarter it shipped. The flag you forget is not neutral — it is unvisited risk with a name like checkout_v2_final_REAL, and it will be involved in an incident you could have deleted instead. This page is the cleanup discipline: an inventory, three fields per flag, a removal ritual, and a monthly sweep that fits in fifteen minutes.
1. Inventory first — and three classes, not one pile
You cannot clean up what you have not listed. One sweep produces the inventory: grep the codebase for flag reads, scan config and feature-flag dashboards, and union the results into a single list. Then split it into three classes, because they have different lifetimes:
- Release flags — gate a rollout. They exist to die: at 100% plus a soak period, the flag is removed. Their whole job is to die on schedule.
- Ops kill-switches — permanent by design, but owned: a named person, a documented off-path, and a drill proving the off-path works. These are the flags you will reach for at 2 a.m.; the runaway automation runbook assumes they flip.
- Experiment flags — die at the decision date, not when someone remembers. Every experiment flag gets an end date the day it is created, and the decision is logged.
A flag missing from the inventory is the dangerous one — not because it is worse, but because nobody counts it, and uncounted risk is the kind that compounds.
2. The three-field rule: owner, kill date, removal task
Every flag in the inventory carries three fields, and a flag missing any one of them is a defect:
- Owner — one named person, never a team. Small-team correction: the engineer who added the flag owns it by default. Teams diffuse; a name on a list does not.
- Kill date — the day this flag is removed or re-reviewed. Release flags: 100% rollout plus 14 days. Experiments: the decision date. Kill-switches: quarterly review. “Temporary” with no date is a permanent flag lying about itself.
- Removal task — filed the day the flag hits 100%, with a ticket ID, into the normal backlog. If removal lives only in someone’s memory, it competes with features and loses every sprint.
Code review enforces this cheaply: a PR that adds a flag without an owner and a kill date gets one comment — “add the three fields” — and does not merge until they exist. Thirty seconds at merge time deletes an hour of archaeology later.
3. The removal ritual (and the off-path drill)
Removal is the step everyone skips, which is how codebases end up carrying 120 flags. The ritual:
- Trigger: flag at 100% for 14 days with zero flips and zero incidents → removal PR goes into the current sprint, not the next one. Removal is not a backlog item; it is the last 10% of shipping the feature.
- Delete everything: the flag read, both code paths’ dead one, the config entry, the dashboard series, and the tests covering the removed path. Grep for stray reads afterwards — half-deleted flags are their own incident class.
- The off-path drill: before a flag earns kill-switch status, flip it off in staging and watch what actually happens. A flag whose off-path has never been exercised is not a safety mechanism; it is a rumor. This is the test the forgotten flag fails — and the reason rollback drills exist in every serious shop.
- Never during a freeze: flag removal is a code change like any other. It waits out the freeze window, and if the removal rollback would be slow, it belongs in a maintenance window instead of a Tuesday afternoon.
4. The monthly 15-minute sweep: OWN or KILL, no third state
Once a month, fifteen minutes, hard stop. Print the flags older than 90 days whose owner, date, or ticket field has gone stale, and give each one a verdict:
- OWN — still earns its existence: refresh the owner, the kill date, and the removal ticket. A kill-switch that survived review re-earns its place for another quarter.
- KILL — everything else: file the removal PR before the sweep ends. Not “next sprint” — the sweep exists because next-spring never comes.
- One escalation rule: any incident where a forgotten or unowned flag was a cause — that flag dies this week, and the post-mortem names the flag, its age, and its ownerless duration. Nothing motivates the three-field rule like a flag that caused an outage with no name attached.
The sweep is deliberately cheap. Fifteen minutes monthly beats a quarterly “flag debt week” that gets cancelled twice and then never scheduled again.
5. What flags must never gate
Some things are not flag material, no matter how convenient it looks:
- Pricing and billing logic. If the flag flips, your invoices change. That is a change-management decision with a paper trail, not a toggle.
- Data migrations and one-way doors. A migration gated by a flag looks reversible and is not. Migrations get the restore-path treatment, not a boolean.
- Anything an auditor must be able to explain. Flags hide state from audits: “which customers saw the old logic?” is a question a flag answers badly and a log answers well.
- Default-on flags with an untested off-path. That is not risk mitigation; it is a permanent code path wearing a safety costume.
6. Worked example
A 40-person SaaS, checkout team. The flag inventory said 120 flags; 38 had no owner, 61 had no kill date, and the median age was 14 months. The motivating incident: a release flag that had gone default-on a year earlier, whose off-path broke silently in a library upgrade — when a slow memory leak made someone try the switch, it did nothing, and checkout ran with doubled latency for nine days before anyone found the flag. One cleanup sprint: 46 flags killed (24 of them dead code paths verified by grep), 11 converted to owned kill-switches with off-path drills, 63 flags total, median age 30 days. Six weeks later a bad deploy hit the same checkout path; the kill-switch flipped in 4 minutes, and the incident report was one page, not one post-mortem.
7. Metrics
- Flags with a named owner: 100% — an ownerless flag is an orphan waiting to page you.
- Flags older than 180 days: zero — either it is a documented kill-switch, or it is debt.
- Median removal lag after 100% rollout: < 2 weeks.
- Kill-switch drill: any flag flippable in < 5 minutes, off-path verified, staging first.
Where this fits
Flags sit at the intersection of three siblings: the change freeze window policy decides when flag changes pause entirely; the maintenance window announcement is where slow-rollback removals belong; the runaway automation runbook is what your kill-switches exist for. For the rest of the estate — the flags, the crons, the access nobody remembers granting — book the small-team ops audit & runbook service.
From the HIVE80lab kit
- The First 30 Minutes — free incident quick-start
- Ops Starter Kit — incident response for small teams — $14
- Ops Starter Kit Vol. 2 — advanced incident response & communications — $27
- Ops Mega Bundle — all 5 kits in one download — $49
Related: the change freeze window policy pauses flag changes along with everything else, the maintenance window announcement schedules the downtime slow removals need, and the runaway automation runbook is what your kill-switches are for.