Feature flags separate deploying code from releasing behavior. A team can ship disabled code, expose it internally, increase the audience gradually, and turn it off during an incident without another build. Without lifecycle discipline, however, flags become permanent configuration and make every code path harder to understand.
Deployment is not release
Deployment moves an artifact into an environment. Release decides who receives new behavior:
const enabled = flags.getBooleanValue(
'checkout-v2', false,
{ targetingKey: user.id, plan: user.plan }
);
return enabled ? checkoutV2(order) : checkoutV1(order);The default is a safety decision. An unproven feature normally falls back to false. A protective kill switch needs unambiguous naming and semantics so operators cannot invert it under pressure.
Four common flag types
| Type | Purpose | Lifetime |
|---|---|---|
| Release | Hide unfinished code and roll out gradually | Short |
| Experiment | Compare variants against a hypothesis | Until enough evidence |
| Ops / kill switch | Shed load or disable a failing integration | Potentially long |
| Entitlement | Grant behavior by plan or contract | Long; manage as policy |
Do not treat a release flag as authorization. Access control belongs on the server with auditability and deny-by-default behavior.
Percentage rollout must be stable
Do not choose randomly on every request. Hash a stable subject:
bucket = hash(flagKey + ':' + targetingKey) % 10000
enabled = bucket < rolloutBasisPointsChoose user, account, or tenant according to the required consistency boundary. B2B workflows often need tenant-level allocation so colleagues see the same behavior.
Evaluation context without unnecessary PII
OpenFeature standardizes evaluation APIs, providers, context, and hooks. Context can include application, region, tenant, plan, and targeting key. Include only attributes required by rules; prefer an opaque identifier over names or email addresses. Order rules clearly: emergency override, internal allowlist, compatibility constraints, percentage rollout, then default.
Client-side or server-side?
- Server-side: business logic, algorithms, integrations, and data control.
- Client-side: presentation changes, while assuming downloaded flags are observable and modifiable.
Never use a client flag to protect secrets or authorization. When both frontend and backend participate, the backend remains authoritative for data-changing behavior.
When the flag system fails
SDKs should cache configuration locally; evaluation should not make a synchronous network call per request. Define each default, acceptable stale-cache duration, provider-not-ready behavior, type mismatch handling, and alerts that distinguish an error fallback from a rule result.
There is no universal fail-open choice. Cosmetic behavior may default on, a new payment path should return to the old flow, and authorization must fail closed.
Observe by variant
Aggregate dashboards can hide a regression affecting a 5% cohort. Split request count, errors, latency, conversion, and business invariants by variant. Record key, variant, reason, provider, and ruleset version while minimizing sensitive context. Set rollback guardrails before rollout and test the kill switch before an incident.
A rollout sequence
- Deploy disabled and verify the old path.
- Enable for developers or employees.
- Canary at 1% for a representative load cycle.
- Advance through 5%, 25%, 50%, and 100% checkpoints.
- Stop or disable when a guardrail fails.
- After stabilization, delete the old path and flag.
Observation time must match the business cycle; five minutes cannot validate an end-of-day job or monthly billing.
Testing without combinatorial explosion
- Unit-test enabled and disabled paths at key decisions.
- Contract-test types, defaults, and required context.
- Integration-test provider failures, timeout, and stale cache.
- Use E2E tests for critical journeys, not every flag combination.
- Run production smoke tests on an internal cohort.
Reducing simultaneous flags and nested branches is more effective than attempting every possible combination.
Cleanup belongs in the Definition of Done
Every flag needs an owner, purpose, creation date, expiry date, default, and removal ticket. At stable 100% rollout, remove the old branch, temporary rules and dashboards, and the control-plane flag. Linting and expiry reports can highlight stale flags.
Production checklist
- Stable key and behavior-oriented name.
- Safe default tested without a provider.
- Consistent hashing by user, account, or tenant.
- No client flag used as authorization.
- Variant telemetry without leaking PII.
- RBAC, audit logs, and an emergency process for rule changes.
- An owner and removal date for every release flag.
Conclusion
Feature flags control release risk; they are not permanent storage for unfinished branches. Safe defaults, deterministic rollout, variant telemetry, a tested kill switch, and disciplined cleanup let teams release in smaller steps, learn sooner, and recover without waiting for another deployment.




No comments yet. Be the first to share your thoughts.