A feature flag, also called a feature toggle, is a runtime switch that decides which code path runs, for all users or for a targeted subset, without a new deployment. Flags separate deploying code from releasing features, enable gradual rollouts, experiments and kill switches, and are evaluated by an SDK against rules and user context.
What a feature flag is
A feature flag wraps a piece of functionality in a condition that is decided at runtime. In code it looks like an ordinary if statement, but the value comes from a flag management system that can change it within seconds, for everyone or for selected users, regions or tenants. That separates two things that used to be one: deploying code to production and releasing a feature to users.
This separation enables trunk-based development with unfinished features merged behind flags, gradual rollouts similar to a canary deployment but at the feature level, A/B experiments and instant kill switches that disable a misbehaving feature without a rollback.
Types of feature flags
A widely used categorization, described by Pete Hodgson on martinfowler.com, distinguishes flags by lifetime and purpose:
| Type | Purpose | Typical lifetime |
|---|---|---|
| Release toggle | Hide unfinished or unreleased features | Days to weeks |
| Experiment toggle | A/B or multivariate tests | Duration of the experiment |
| Ops toggle | Kill switches, load shedding, fallback modes | Short-lived or permanent |
| Permission toggle | Features for specific plans, beta users or internal staff | Long-lived |
The distinction matters because each type needs different governance. A release toggle that survives for a year has become technical debt; a permission toggle is part of the product.
OpenFeature: the open standard
Most flag vendors ship proprietary SDKs, which makes flag checks a source of vendor lock-in scattered across the codebase. OpenFeature, a CNCF project that reached incubating status in December 2023, defines a vendor-neutral evaluation API with SDKs for many languages. Its core concepts are:
- Evaluation API: typed calls such as
getBooleanValue("new-checkout", false, context)with a default value. - Providers: adapters that connect the API to a specific flag backend, commercial or self-hosted, such as the reference implementation flagd.
- Evaluation context: attributes such as user ID, plan or region that targeting rules use.
- Hooks: code that runs before and after evaluations, for example to emit telemetry.
Switching vendors then means changing the provider, not every flag check.
Why feature flags need observability
A flag change is a production change, just like a deployment, but it often bypasses the deployment pipeline and its markers. When the error rate rises at 14:02 and nothing was deployed, the cause may be a flag toggled at 14:01. To make that visible:
- Record evaluations. The OpenTelemetry semantic conventions for feature flags define attributes such as
feature_flag.key,feature_flag.result.variantandfeature_flag.provider.namefor evaluation events. These conventions are still marked as in development, and some names changed in 2025, so pin the version you use. - Record changes. Send flag change events from your flag system as annotations, alongside deployment markers.
- Compare variants. Split latency and errors by variant to see whether the new path behaves differently.
OpenFeature hooks are a natural place to add these attributes to the active span, so every trace shows which variant served the request.
Example: a flag-driven rollout
An illustrative rollout of a new checkout flow behind the flag new-checkout:
- Deploy the code with the flag off for everyone. Nothing changes for users.
- Enable it for internal staff and verify traces, errors and business metrics.
- Expose 5% of customers, then 25%, 50% and 100%, holding each step long enough to collect meaningful data.
- At every step, compare the new variant with the old one on latency, error rate and conversion. If the error budget burns too fast, switch the flag off, which takes effect without a redeploy.
- After a stable period at 100%, remove the flag and the old code path.
Percentage rollouts should be sticky: the same user must consistently get the same variant, usually by hashing a stable identifier, or user experience and measurements both become noisy.
Best practices
- Give every flag an owner and an expiry date, and remove release toggles as soon as the rollout is complete.
- Use safe defaults. If the flag service is unreachable, the default value must be the safe behavior.
- Tie rollouts to SLOs. Increase exposure step by step and stop when error budget burn rises.
- Keep flag logic shallow. Nested flags multiply the number of code paths you need to test.
- Audit changes. Who changed which flag, when and for whom should be traceable for compliance and incident analysis.
Common mistakes
The most common problem is flag debt: hundreds of stale flags nobody dares to remove. Others are putting user IDs or personal data into flag keys or telemetry attributes, evaluating flags in tight loops with remote calls, and treating flag changes as harmless configuration that needs no review or monitoring.
How Obseria helps
Obseria ingests OpenTelemetry spans and events with feature flag attributes, so you can filter traces and errors by flag key and variant and compare variants side by side. Deployment tracking places releases on the same timeline, and SLOs with error budgets, included in every plan, give rollouts a clear stop criterion.