Cleaning Up Feature Flags: The Art of Not Leaving a Mess

Share

Cleaning Up Feature Flags

You said you’d remove that flag after launch. You lied. It’s been six months and the flag is still in appsettings.json, the if-else is still in your controller, and nobody remembers which state is “on.” This is how codebases turn into haunted houses.

Why Cleanup Matters

Dead feature flags are technical debt with teeth. They add branches to your code that nobody tests. They confuse new developers who don’t know the history. They inflate configuration files and make deployments harder to reason about. And they grow exponentially — every flag you don’t clean up makes it harder to clean up the next one, because the cognitive load of understanding your system keeps increasing.

The cost of removing a flag is low right after the feature ships, when the context is fresh. It gets dramatically more expensive the longer you wait.

Track Every Flag

You can’t clean up what you can’t find. Maintain a registry of every active feature flag in your system — name, purpose, owner, date created, and expected removal date. This can be a spreadsheet, a column in your issue tracker, or a dedicated page in your internal docs. The format doesn’t matter as much as the habit.

When you add a flag, add a row to the registry. When you remove a flag, delete the row. If the registry has flags with no owner or no removal date, those are your highest-priority cleanup targets. Or skip the spreadsheet entirely and use a flag management tool that tracks this automatically, with history — and doesn’t require you to remember to update the shared doc.

Set Expiry Dates

Every flag should have a planned removal date when it’s created. Release toggles should be removed shortly after the feature ships — two weeks is a reasonable default. Experiment toggles should be removed when the experiment concludes. Ops toggles and permission toggles may be permanent by design, and should be explicitly marked as such.

If a flag has been alive longer than its planned expiry and hasn’t been deliberately extended, it’s already a zombie. Treat it accordingly.

Make Cleanup Part of the Process

Flag cleanup doesn’t happen unless someone is responsible for it. Add a cleanup step to your feature completion checklist. Include “remove the feature flag” as a ticket in the same sprint as the feature launch.

Some teams set automated alerts when flags exceed their planned lifetime. Others include flag counts in engineering dashboards. The specific mechanism matters less than having a mechanism at all.

How to Actually Remove a Flag

Removing a flag is not just deleting an if statement. Here’s the full checklist:

  1. Determine which state the flag should be permanently in (almost always “enabled” if the feature shipped).
  2. Remove the flag check from the code and keep only the code from the enabled path.
  3. Delete the disabled code path entirely. Don’t leave it commented out.
  4. Remove the flag definition from configuration files and the flag management system.
  5. Update or remove tests that were specifically testing the disabled state.
  6. Delete the flag from your registry.
  7. Deploy and verify.

Step 3 is where most people get lazy. Commented-out code is not the same as deleted code. Delete it.

The Goal

A well-maintained codebase has only the flags it needs, each one documented, owned, and scheduled for removal. Cleanup is not a one-time event — it’s an ongoing practice.

The only good zombie flag is a deleted one. You already knew that. Now do it.