Retire a Feature Flag Safely
Confirm full rollout, remove the old code path and flag checks, deploy in the safe order, and delete the flag configuration without leaving dead branches.
Objective
Remove a release toggle after a feature is fully launched, reducing branch complexity and configuration drift.
Environment
- A flag system with evaluation logs or usage analytics
- A codebase with the old and new paths behind the flag
- A deploy pipeline and a rollback plan
- Tests covering both paths
Steps
1. Confirm the rollout is complete
Verify the flag evaluates on for 100% of intended traffic and has stayed stable through a full business cycle.
Expected state: No supported cohort still needs the off path.
2. Remove the off branch
Make the new path unconditional, delete the old code, and remove the flag check. Update tests to cover the remaining behavior.
Expected state: The code has one path and the tests pass.
3. Deploy before deleting configuration
Deploy the code that no longer reads the flag, verify it in production, then delete the flag configuration.
Expected state: No running instance depends on the flag when it is removed.
4. Clean up and review
Remove documentation, dashboards, and alerts that reference the flag; confirm no other service evaluates the same flag.
Expected state: The flag is gone from code, config, and operations.
Decision points
Should the old path be kept for rollback?
- Remove it after a stable rollout window
- Keep it indefinitely behind the flag
Keep it only for the agreed rollback window; indefinite flags become permanent branching debt.
Can the flag config be deleted before the code deploy?
- No, deploy code first
- Yes, if the default equals the desired behavior
Deploy code that no longer reads the flag first, then delete the config; otherwise old instances may evaluate a missing flag.
Expected outcome
The feature runs without a toggle, the old path and flag configuration are removed, and no service still depends on the flag.
Verification
Search the code and configuration for the flag name, confirm zero evaluation requests after removal, and run the full test suite plus a canary check on the unconditional path.
Cleanup
Archive the rollout record, update the feature catalog, and delete stale dashboards.
A flag is temporary by design
Release toggles exist to separate deploy from release. Once the release is complete, the flag is debt: every branch doubles the states to test and reason about. Retiring it is a small migration with its own order and verification.
1. Confirm 100% on and stable
2. Remove the off branch and flag check
3. Deploy and verify
4. Delete the flag configuration
5. Remove docs, dashboards, and alerts
Deploy before deleting config
Old instances may still evaluate the flag during a rolling deploy. Remove the code dependency first, verify the unconditional path, then delete the configuration. Deleting the flag before the code can make old instances fall back to a default that changes behavior.
Prove the flag is gone
Search code, configuration, and infrastructure for the flag name. Check the flag system for evaluation requests after removal. Run the tests that covered both paths; after removal, they should cover the single remaining path. If another service evaluates the same flag, coordinate before deleting it.