Feature Flags: Give Temporary Flags an Expiry Decision
A fictional export flag still has an unverified worker. Use its retirement card to choose removal, extension or a supported operating control.
A temporary feature flag should reach a decision date, not quietly acquire another year of life. At that review, choose one of three outcomes: remove the temporary decision from the system, extend it for a named unresolved dependency or retain it as a supported operating control. Each outcome needs evidence about the consumers and behavior that will remain.
A date alone cannot make that choice. Automatically turning a flag off may restore an obsolete path. Deleting its configuration may expose an older client's fallback. Removing the last visible conditional may leave a scheduled worker or a session created under the flag outside the review. The expiry decision should identify exactly what ends and what continues.
The website case separates a switch from the state it creates
In its repeat-onboarding session case, Pharos Production describes a temporary demo mechanism that preserved the reader's stored profile. Stas Rysin's October 27 engineering note explains that a runtime switch could add an onboarding-pending mark to the signed session. Successful Continue or Skip cleared that mark and returned the changed cookie. A failed save did not clear it.
This was a testing and demonstration flow, not a general release-flag retirement protocol. The source also limits the result to the request and session boundary; it does not promise that another tab's previously issued cookie changes instantly.
The useful connection is a question for any retirement review: what state can remain after the switch changes? Do not assume that stopping new activation also disposes of already created state. The export example below is a separate, fictional review exercise. Its flag, builds, dates and decisions are proposed illustrations, not reported details of that implementation.
Make expiry a review signal before making it an action
Unleash's current feature-flag documentation states:
Unleash marks all flags as potentially stale automatically once they pass their expected lifetime.
Unleash, Feature flags: feature flag state
That statement concerns lifecycle state. It should not be read as a promise that an expected lifetime disables runtime behavior or removes application code. A stale indication helps start cleanup work; the effect of a runtime configuration change is a different question. Check how the chosen platform represents each operation. Give the review a deliverable: a retirement decision with an owner and evidence. For an open dependency, record it and assign a next review. A flag becoming an operating control needs a continuing purpose and support obligations. When removal is ready, name the behavior that becomes unconditional and the consumers that must be upgraded first.
Keep the decision date separate from any scheduled runtime change. A reviewed change can have an execution time, but reaching a calendar date does not establish that it is safe to execute. A review reminder should not accidentally become an instruction to flip a production value whose consequences nobody assessed. Also distinguish overdue work from unknown ownership. A flag with a missed review and a current accountable owner can enter a cleanup queue. A flag with no responsible team needs ownership resolution before a destructive operation is scheduled. Treat an empty owner field as missing evidence. It does not authorize deletion.
Classify the purpose that remains
A release flag usually exists to introduce a particular change. Its completion question is whether the intended behavior can stand on its own. An experiment flag has a different completion question: which decision ended the experiment, and what happens to the rejected variation? A lasting operational control needs both supported behavior and an owner after the launch is forgotten.
Do not classify by how long a flag has already existed. A temporary flag can become old through neglect. A frequently used switch can still be temporary while a migration completes. Conversely, an infrequently used emergency control may have a legitimate continuing purpose. The classification should describe why the branching behavior must remain.
Pete Hodgson's Feature Toggles article distinguishes toggle categories and their carrying costs. Use that distinction to avoid applying a release-cleanup rule indiscriminately to every toggle. The local inventory still needs a decision for each actual control; a category label is not proof that its implementation remains useful.
Write the continuing purpose in operational terms. Who would change the value, under which condition and with which expected effect? If the answer is simply that someone might need the old code someday, investigate what recovery actually requires. A flag cannot preserve a recovery path whose dependencies have already disappeared.
A feature flag also should not substitute for authorization. Keeping a feature hidden and deciding whether a caller may perform an operation are separate responsibilities. Retirement of a presentation or rollout flag must preserve the application's actual access checks. That boundary matters especially when an old branch appears to be unused because only privileged users can reach it.
Put the decision on one retirement card
The fictional flag F-31, export_csv_v2, selects a new export encoder. The proposed review is November 10, 2026. The intended final behavior is the new encoder. The web service is known to use it, but the scheduled export worker's deployment evidence is incomplete. This card is a populated example of the evidence a reviewer should request.
| Field | Fictional F-31 entry | What the reviewer must decide |
|---|---|---|
| Purpose | Introduce the new CSV encoder | Has this release objective ended? |
| Accountable owner | Export service maintainer | Who owns cleanup and unresolved consumers? |
| Intended retained behavior | New encoder without the temporary choice | Which path survives code removal? |
| Known consumers | Web service W-8 and scheduled worker B-4 | Which deployed artifacts can still evaluate the key? |
| Audience and exceptions | Normal exports; worker coverage unresolved | Does rollout evidence cover the full intended population? |
| Created state | Queued export work and generated files | What needs compatible completion or continued interpretation? |
| Fallback | Older worker can select the old encoder when the key is missing | What happens after configuration disappears? |
| Review evidence | Web result available; worker deployment proof missing | Is removal ready, or does a named dependency block it? |
| Decision and next action | Hold removal; resolve worker evidence | What must change before another removal review? |
The card deliberately does not label the missing worker evidence as a failed deployment. Unknown is enough to prevent a confident retirement decision, but it does not establish what the worker actually runs. Ask for its deployed artifact and relevant execution path before choosing the remedy.
Preserve the decision's scope. A decision to remove F-31 from the web service does not establish that the whole flag can be archived. A decision to extend the flag does not approve every existing exception forever. Link each action to the consumer and behavior it addresses so a later reviewer can tell what the decision covered.
Walk the same card through three decisions
At the proposed November 10 review, the worker evidence is still unknown. The defensible outcome is a bounded extension with an assigned investigation, not a claim that the worker failed. Leave the current runtime behavior explicit. The maintainer should obtain the artifact identity and check how queued work chooses its encoder before recommending configuration removal.
Suppose that investigation later establishes a supported worker release with no reference to the temporary key. This is a hypothetical changed input, not an executed result. The next review can then consider retirement against the remaining acceptance conditions. The relevant evidence changed; the calendar alone did not make the decision safer.
A different investigation might establish a continuing requirement to switch between two supported encoders. That would support reviewing an operating-control design, including the output contract and responder instructions for each choice. It would not justify retaining an invalid old encoder just to avoid cleanup. A permanent label cannot repair an unsupported branch.
| Review outcome | Required explanation | Evidence that changes the next action |
|---|---|---|
| Remove the temporary choice | Intended behavior is fixed and remaining-consumer conditions are satisfied | Supported artifacts and post-removal checks cover the retained path |
| Extend temporarily | A named dependency prevents a removal decision | Assigned worker investigation and a dated review of its result |
| Retain as an operating control | Branching remains a supported operational requirement | Owner, valid behavior on each side and a usable operating procedure |
Keep the actual decision on the card. A discussion that produces three possible actions but selects none has not completed the review. Where the evidence supports only an extension, say what remains unresolved. Where removal is chosen, distinguish the approval from the deployment and archival steps that still need to happen.
Inventory consumers before interpreting zero usage
Start with the code references the team knows, then check the deployment surfaces that can execute them. Include scheduled work, administrative tools and older supported clients where they exist. A repository search identifies candidate references; it does not prove which build is running or whether a branch can still be reached.
Record a deployed artifact for each relevant consumer. In F-31, W-8 and B-4 are separate evidence rows even if they originate in one repository. A web release cannot establish the worker's cleanup state. If a worker runs infrequently, an empty recent metrics window may simply mean its next execution has not happened yet.
Zero evaluation counts need a denominator and a coverage statement. Which applications report evaluations? Which environments and time interval are included? Can evaluation occur without telemetry reaching the dashboard? A quiet chart is useful evidence within its known coverage, but it does not establish absence across consumers the instrumentation cannot see.
Dynamic flag keys deserve attention too. A search for a literal name can miss a key assembled from a prefix, loaded from a registry or passed through a wrapper. Review the relevant configuration and call sites rather than claiming that one search result supplies a complete inventory. Document any surface that remains outside the inspection.
When evidence is old, keep its age visible. A reference scan from a previous branch and a current deployment manifest answer different questions. The review should connect the source inspection to the artifact actually eligible to run. Otherwise a tidy cleanup pull request can coexist with an older deployed consumer that still expects the flag.
Review state and work already created under the flag
A flag can affect more than the next request. It may influence a session, an asynchronous job or a record whose interpretation persists after evaluation. The retirement card should identify these effects and the contracts needed to finish or read them. It should not assume that the configuration service owns their lifecycle.
For F-31, inspect how a queued export selects its encoder. Does the job capture an encoder choice when created, or evaluate the flag when it runs? Those designs can produce different behavior during cleanup. The example does not assume either implementation. The owner must establish which one exists before deciding how pending jobs will complete.
Generated files create another boundary. Removing an encoder branch does not rewrite previously downloaded exports or change the schema their consumers already expect. If the new format requires a version marker or a different reader, retain the necessary compatibility contract. Avoid describing code cleanup as a repair of every output previously produced.
For a session-based mechanism like the website case, ask how already issued state reaches its terminal condition and which response carries the update. That is a proposed review question, not an assertion that disabling the source's runtime switch leaves a particular cookie unchanged. Existing-state behavior needs evidence from the implementation being retired.
Keep the work bounded by actual effects. Do not create a speculative inventory of every possible database and client. Follow the flag's documented decisions, inspect the state those decisions can create and record the places where the evidence stops. An explicit unresolved boundary is more useful than a long list of hypothetical risks with no owner.
Extend a temporary flag with a dependency and a new review
An extension should explain what prevents retirement. In the fictional F-31 review, the dependency is worker evidence, not a vague request for more confidence. The maintainer can assign an investigation, retain the temporary choice for the affected scope and set a new review date. The decision should identify what evidence will end the extension.
For example, a proposed November 17 review could require the worker's deployed build, its missing-key behavior and an agreed handling path for queued work. Those are illustrative acceptance inputs, not a claim that seven days is an appropriate universal extension. Set the interval from the work that must happen and the consequences of retaining the branch.
Preserve the prior review record. Replacing November 10 with November 17 without an explanation erases the overdue decision instead of resolving it. A small history should show the old date, the unresolved dependency, the current owner and the new commitment. Repeated extensions then reveal a persistent architecture or ownership problem.
Keep the flag's current runtime state explicit during the extension. Postponing cleanup does not necessarily mean changing rollout targeting or reopening an experiment. If runtime behavior must also change, describe that as a separate reviewed action. The person resolving an ownership ticket should not inadvertently alter what users receive.
Retain an operating control deliberately
A temporary release flag may reveal a continuing need, such as a supported load-shedding or emergency-disable control. Reclassifying it is a design decision. Define the conditions for using it and the behavior supported on each side. Remove rollout-specific rules that no longer serve that purpose rather than retaining the entire launch configuration by default.
Name an operating owner and a replacement when that owner changes. Document who can alter the value, where the change is recorded and how responders verify its effect. An emergency switch that nobody can identify during an incident is not adequately supported merely because it remains enabled in the dashboard.
Exercise its fallback behavior on a suitable schedule. A permanent control may receive fewer routine branch executions than a temporary release flag, so a dormant path can lose compatibility quietly. The review should identify what must be tested and which observation would trigger another design decision. The schedule belongs to the system's operating requirements.
LaunchDarkly's technical-debt guide distinguishes temporary and permanent flags and describes including cleanup or permanent classification in the definition of done. The principle applies to the local decision: permanence should add an explicit support contract. Changing a metadata label alone does not create that contract.
Remove the temporary decision in a controlled sequence
First specify the retained behavior and the supported consumers. Then remove the temporary branch and its evaluation from the relevant code, preserving required authorization and output contracts. Deploy those artifacts through the normal release process. Only after the remaining-consumer conditions are satisfied should configuration retirement proceed.
Deleting the flag first can change the behavior of code that still asks for it. The consumer may use a local default or a cached value; its actual behavior depends on the implementation. For F-31, an older worker with an old-encoder fallback is precisely why absence of the key must be examined before archival.
LaunchDarkly's archiving documentation describes archiving and restoration as platform operations. Treat the platform's checks as evidence with a stated coverage boundary. A successful archive action does not prove that an unsupported binary, dynamically generated key or external consumer was included in the code inventory.
Keep the cleanup change focused enough to review. Combining flag removal with a new export format and an unrelated refactor makes a regression harder to attribute. Google SRE's Canarying Releases discusses evaluating changes through limited exposure. Apply the release discipline appropriate to the service; cleanup is still a behavior change when it removes a runtime choice.
Archive or retain historical configuration according to the platform and project policy. Avoid reusing an old key for an unrelated feature while older artifacts might still reference it. The review packet should identify how history remains discoverable even after the flag is no longer part of active operation.
Verify the behavior after removal, not just the missing name
The proposed acceptance checks begin with ordinary supported requests and the intended retained output. Verify that the new artifact works without the temporary configuration. Then test configuration unavailability and the relevant local fallback. An absent conditional in source is insufficient if another wrapper still supplies the old choice.
Check the older supported consumer separately. If it still requires the flag, either upgrade or retire that consumer under an agreed policy before declaring global removal complete. If it is no longer supported, identify the enforcement or deployment boundary that prevents it from returning. An informal belief that nobody runs it is weak evidence.
Exercise pending work under the established job-selection contract. For F-31, that means a queued export created before cleanup and an export created afterward. Compare the output schema and the recorded encoder identity where available. The checks should establish continuity for the behavior the team actually supports, not force both jobs to use an invented implementation.
Include exceptions and restricted audiences in the review when they remain relevant. A rollout can reach its target for the main web population while an administrative or tenant-specific rule remains. Identify whether that exception is still intentional. These are proposed implementation checks; no export service, worker or customer system was tested for this article.
State what rollback can still restore
After code removal, changing the old flag value may no longer affect the new artifact. Recovery might require redeploying a previous build, restoring compatible configuration or following a different operating procedure. Name that path before retirement so responders do not discover during an incident that the former switch has become inert.
Check whether the previous artifact still works against current dependencies and data. A retained binary is not enough if its schema or external service contract has been removed. The retirement review should distinguish a usable recovery target from an archived file that only looks like one.
State changes already made by the feature need their own handling. Restoring a branch does not necessarily reverse a generated file, an external notification or a committed record. Record the effect boundary and the owner of any repair process. Do not present a flag toggle as an automatic undo operation for work it cannot reverse.
Once the decision is complete, update the runbook and the relevant release record. Preserve the old flag's identity as history while making the current recovery action easy to find. Retiring a temporary control should leave responders with a more accurate operating picture, not merely a smaller list of switches.
Make the next review produce an accountable outcome
When a temporary flag protects behavior across a backend and its workers, Pharos Production's backend development services provide a relevant implementation and architecture scope. A useful review request includes the flag's purpose, deployed consumers and proposed retained behavior. It does not assume that an age threshold or a dashboard status has established removal readiness.
Bring the retirement card to the owner who can decide the remaining scope. Record remove, extend or retain as an operating control, with evidence and a next action for any unresolved consumer. Revisit that decision when a supported build changes, a new consumer appears, a fallback becomes invalid or an operating requirement changes. Temporary should end in an explicit decision someone can explain.
More insights to read
- Repeat Onboarding Without Resetting the Reader's Profile
- Reducing technical debt from feature flags
- Canarying Releases
- Feature Toggles (aka Feature Flags)
- Feature flags
About the author

Dmytro Nasyrov. Photo supplied by the author.
Written by Dmytro Nasyrov PhD, software architect with 24 years of production experience. Dmytro is the founder and CTO of Pharos Production. He works on production software architecture for FinTech, AI, Web3 and blockchain systems.