Deployment is when the code arrives in production. Release is when someone can actually use it. Confusing the two is one of the quickest ways to make every deployment a little tense moment.
The feature flag serve to put space between these two moments. You can deploy today, fire up tomorrow for the internal team, then for a pilot customer, then for 10% of users. If something goes wrong, turn off the flag. You don't necessarily have to rollback the entire release.
The flag is not just an if
Technically it is often a if. Culturally it is much more.
if (await flags.isEnabled('checkout.v2.enabled', context)) { return newCheckout(input); } return oldCheckout(input);
That little if can represent a gradual rollout, an experiment, a migration, an enterprise permit or an operational kill switch. The problem is that if you don't manage it well, it can also become technical debt that stays in the code for two years.
Where does OpenFeature come in
OpenFeature is an open specification for evaluating feature flag with a common API. The idea is simple: your application code should not depend directly on the vendor or internal system you use for flags.
The app asks:
const enabled = await client.getBooleanValue('checkout.v2.enabled', false, { targetingKey: user.id, plan: user.plan, country: user.country, });
The provider decides where the rules come from: SaaS, file, internal service, flagd, GitOps configuration. If one day you change feature flagging backend, the application doesn't have to be rewritten everywhere.
This separation seems like an architectural detail, but it is felt as the project grows.
Context is half the battle
An on or off flag for everyone is useful, but limited. Progressive delivery lives in context:
- internal or external user;
- free or enterprise plan;
- village;
- organization;
- app version;
- stable percentage of traffic.
The important key is targetingKey: it must be stable. If it changes with every request, a user can end up once in variant A and once in variant B. For an experiment it's terrible, for a checkout it can be disastrous.
A sensible rollout
A flow I like is this:
- deploy with flag off;
- ignition for developers and QA;
- switch-on for a pilot customer or tenant;
- 5% rollout;
- rollout at 25%;
- 100% rollout;
- removal of old code and flag.
The often forgotten point is the last one. A temporary flag must have a death date. If it stays forever, every future refactor will have to ask: "but is this branch still useful?".
Kill switch: prepare them first
The kill switch is the flag that saves you when an external dependency starts messing with you, a job consumes too many resources, or new logic produces strange errors.
A good kill switch must be:
- easy to find;
- documented in the runbook;
- tested occasionally;
- observable when activated;
- independent, as far as possible, from the part that could break.
The worst thing is to discover during the accident that the flag exists, but no one knows if it still works.
Observability or not progressive delivery
Turning on a feature at 10% without looking at metrics is just optimism with multiple steps.
Each rollout should answer simple questions:
- have errors increased?
- has the latency changed?
- do users complete the flow?
- are there more tickets or retries?
- does a variant impact only one segment?
OpenFeature supports hooks around flag evaluation. They are useful for logging errors, adding metrics or linking the rating to a trace.
Naming and ownership
Names matter. new_ui says nothing. checkout.v2.enabled says much more.
For each flag I would mark at least:
- name;
- description;
- owner;
- safe default;
- reason why it exists;
- date or condition of removal.
An ownerless flag is almost always a flag that no one will clear.
Where to evaluate them
Frontend, backend or edge? Depends.
If the flag is for layout, copy, or onboarding, the frontend is fine. If it concerns permissions, billing, limits or sensitive data, it must be on the backend. If it involves routing or high-traffic experiments, the edge may make sense.
The simple rule: the frontend can improve the experience, but it shouldn't be the only security barrier.
Conclusion
The feature flag done well change the relationship with production. They don't eliminate the risk, but they make it smaller and more manageable. You can release in slices, observe, stop, go back, learn.
OpenFeature adds a clean foundation: a common API, interchangeable providers, and a tidier way to grow the system. But the discipline remains yours: safe defaults, clear names, metrics, owners and cleanliness.
The best flag is the one that helps you release calmly and then disappears when it is no longer needed.