A successful rollout leaves a second job

A feature flag lets a team choose a code path at runtime, but its presence creates another decision each time that path is evaluated. After a feature becomes the intended standard experience, the old conditional may still exist in a website, worker, mobile app or shared library. Retiring the flag means choosing the permanent behavior, removing obsolete branches, and checking all environments before removing configuration. LaunchDarkly's archiving guidance specifically says to remove code references before archiving because an archived flag can return the fallback value defined in code. That is a provider-specific consequence with a general lesson: switching a flag on for everyone is not the same as removing it safely.

This question differs from deciding how to release a website change. The release may have succeeded weeks ago; the remaining risk is that a hidden old branch can unexpectedly run, or that removing a shared flag changes an overlooked process. Give every temporary flag an owner, a purpose and a proposed review point. Do not invent a universal expiry period, because an operational safety switch and a temporary rollout flag have different reasons for existing. Microsoft's feature management guidance distinguishes simple switches, rollouts and experiments. For retirement, first establish which role this flag actually serves; a long-lived protective control may deserve a different maintenance plan than a completed rollout toggle.

Define what finished means

A flag is not ready for deletion merely because its dashboard shows one variation enabled. Check the intended audience and the environments that matter: production website, background workers, internal tools, scheduled jobs and any client versions that may remain in use. If the feature is meant for all eligible customers, confirm whether exclusions, regional rules or account-specific overrides still have a business reason. OpenFeature's evaluation-context specification explains that targeting can depend on subject keys and contextual attributes such as locale or organisation membership. That means a global-looking percentage or default is not always the whole rule. Record the intended final behavior in words that a product owner can review.

Check evidence of use without turning missing telemetry into proof. Evaluation logs, configuration history and code searches may show where the flag is still called, but each has blind spots. A rarely run month-end job might not appear in a short observation window; a hard-coded key assembled at runtime may evade a simple text search. Where available, combine runtime observations with repository search, deployment inventory and a conversation with the process owner. If no trustworthy measurement exists, say so and test the suspected paths directly. The acceptance question is whether the permanent branch behaves correctly wherever the flag can affect a customer or an operational decision.

Map every dependency before editing

Search for the flag key across application code, tests, infrastructure configuration, templates and operational scripts. Include aliases if the team renamed the flag. Look for both the evaluation call and the consequences of each returned value: a route, button, data field, background action or third-party call. LaunchDarkly documents code-reference tooling for locating flag keys, but its availability depends on a customer's plan and its scanner also depends on the key being represented in code in a way the tool can find. A team without that service can still conduct a deliberate search and keep a list of affected components. The purpose is to understand behavior, not to collect a long list of text matches.

Map configuration separately from code. A flag may have different targeting rules in development, staging and production, and a shared project can carry the flag across environments. LaunchDarkly warns that archiving a flag removes it from every environment in its project. Therefore a seemingly local cleanup can affect a testing flow or another application still evaluating the same key. Identify who owns each environment and whether any dependency uses the flag as a prerequisite. If the team cannot explain one reference, keep the retirement task open until it is understood or safely isolated. Deleting unknown configuration to tidy a dashboard is not an adequate business reason.

Replace the decision with one clear path

The implementation change should make the intended branch unconditional, remove the obsolete branch and preserve the business checks that matter. Do not simply replace a flag evaluation with a literal true value and leave the old branch in place. That keeps dead code and makes later readers wonder whether it still matters. Review tests at the same time: retire tests that only prove the old variation, while retaining tests for the customer outcome, authorisation, data writes and error handling of the chosen path. If the old branch wrote data in a different format, check that existing records and downstream readers remain understandable after cleanup.

Deploy the code cleanup while the flag configuration still exists, using the normal release checks for that application. This ordering gives the team a chance to observe whether any deployed component continues to evaluate the key. It is a proposed safe sequence, not a guarantee that every provider behaves identically. Confirm the active app versions, especially mobile clients or delayed workers that cannot be updated instantly. Only after all relevant code paths are updated and checked should the team remove or archive the configuration according to its provider's semantics. Keep the ability to restore service through normal deployment procedures; a retired obsolete branch should not be treated as a permanent rollback plan.

A booking reminder example

Consider a service business that once used a flag to choose between an old email reminder and a new reminder workflow. The new path has become the intended behavior for eligible bookings. The team finds the flag in the booking website, a scheduled sender and an internal preview tool. A quick look at the website alone would miss two paths. The owner writes the desired final rule: eligible bookings use the new reminder, ineligible bookings receive no reminder, and the customer-facing confirmation remains accurate. These are illustrative rules for this example, not claims about an actual company's system or legal notice obligations.

The team tests a normal booking, an ineligible booking, a cancelled booking and a sender retry. It verifies that the new path does not send duplicate messages and that the preview tool matches the actual rule. Next it removes old-path code from each component, deploys those changes and confirms all active workers run the updated version. If an old mobile app still calls the flag, the task remains open until that version is addressed. Once there are no relevant references and provider behavior has been checked, the configuration can be archived or removed. The value of this sequence is the explicit completion evidence, not an arbitrary number of days left switched on.

Close the task with evidence

A concise retirement record should name the flag, its owner, the chosen permanent behavior, affected components and environments, the test results, and the configuration action taken. Link to the code change and note any deliberately retained operational switch that has a separate purpose. If the team uses a provider with fallback behavior on archive, record the fallback value and why no live client can rely on it. Do not infer safety only from an absence of evaluations over a short period. A closure record should let a future maintainer understand why the alternate path vanished and where the current business rule lives.

If a dependency remains, stop at a truthful partial state: the code cleanup may be ready for one component, while the flag itself cannot yet be archived. Identify the blocker, its owner and the next test, then keep the configuration controlled. This is not a failed editorial answer; it is the correct decision when evidence does not support retirement. For a small team, a modest recurring review of temporary flags helps prevent forgotten branches from accumulating. The useful habit is to ask whether each flag still changes a real decision, whether its owner still knows why, and what evidence would permit its eventual removal.

Keep a separate decision for the old data path when the flag governed more than presentation. A flag that once selected a pricing calculation, notification queue or record format can leave stored data that still needs a reader, even after all current users see the new experience. Inventory what the retired branch created, who consumes it, and whether historical records must remain readable. Remove the conditional only after the chosen path can handle those records or a deliberate migration has been tested. If the old branch was a safety control for an external dependency, decide whether a new operational control is needed before deleting it. This is why a code search and a dashboard status are starting evidence rather than a complete retirement decision: persistent effects can outlive the flag evaluations that created them.

Before you proceed

  • State the permanent behavior and inventory all consumers of the flag.
  • Remove old code paths and test active components before archiving configuration.
  • Document any remaining dependency and keep the flag controlled.

Sources & further reading