Provider-agnostic feature flagging
Often, the initial choice of subject is incorrect.
To identify the correct subject, ask: What is the primary unit for releasing, selling, and supporting features in your product? Who experiences changes when a feature is enabled or disabled? The correct subject should typically match the entity reflected in contracts, deployment boundaries, or operational responsibilities. When in doubt, choose the smallest unit that reflects meaningful delivery or risk for your business.
Flag tooling originated in consumer products, where the default subject is the individual user and rollouts typically target a percentage of users. Most SDKs and documentation examples follow this approach.
In a multi-tenant B2B product, the individual user is not the relevant unit. Features are enabled for customer accounts, reflecting how the product is sold, supported, contracted, and deployed.
If the user remains the subject, each rollout requires translating account-level decisions into user-level terms. Maintaining this translation becomes complex as accounts change, leading to discrepancies between intended and actual rules.
Set the tenant as the evaluation subject, while retaining user and organization traits for more granular targeting when necessary. This approach reduces translation, minimizes hidden costs, and makes tenant-level evaluation the default.
For example, consider a SaaS platform where features are enabled per customer account (tenant), but within each account you want to offer early access to a new feature only to a subset of users, such as account administrators. In this setup, the flag evaluation uses the tenant ID as the primary subject, ensuring that the feature is controlled at the account level. At the same time, user traits like user role can be included in the targeting rules, allowing the feature to appear only for admins within early access tenants. This makes it clear and efficient to manage both broad rollouts and targeted exceptions using the same evaluation model.
In general, if a tool’s default subject does not align with your delivery unit, adjust the subject instead of maintaining a translation layer.
Segments should correspond to the release lifecycle.
Typically, segments are arbitrary cohorts named per feature, each interpreted differently by its creator. Over time, this results in a flag system that is difficult to interpret, especially when original authors are no longer available.
Instead, define segments based on release stages such as internal development, staging and validation, controlled early access, and general availability. Use consistent terminology across all features to reduce ambiguity.
An additional benefit is improved clarity for non-technical stakeholders. For example, support staff can easily determine whether a customer has access to a feature.
Server-side authority
Deciding where evaluation occurs is distinct from selecting a provider, and it affects whether the client and server can produce inconsistent results.
The server assembles the context, performs the evaluation, and returns the resolved state through the existing API contract. The client simply consumes this resolved state without further evaluation.
This approach centralizes the construction of targeting context, eliminates provider-specific logic from browser bundles, and allows provider changes to be made behind an existing client contract. The trade-off is that the server becomes the single point of failure for this process.
This eliminates the possibility of disagreement, as only the server determines the outcome. In contrast, client-side evaluation can result in inconsistent answers due to differences in context freshness.
The trade-off is that the resolved state is a snapshot, so flag changes propagate according to your existing API refresh schedule. If you require near-instant updates, this approach is not suitable. It offers faster evaluation but slower updates and delayed visibility.
The coupling, and the fix that is not one
If you call a vendor SDK at each decision point, the product code becomes aware of the specific vendor in every location where a feature is gated.
This dependency remains unnoticed while the vendor operates reliably. However, if the provider is slow or unavailable, it escalates from an infrastructure issue to a product issue wherever flags are used.
It may appear that switching to a better provider is the solution. While a new vendor may be more reliable, the underlying coupling remains, so failures persist in the same form and migration costs recur. Caching and fallbacks reduce impact but do not address the root cause.
The key question is not why the provider failed, but why its failure affected your users.
A vendor-neutral evaluation layer addresses this issue. OpenFeature, the CNCF specification, is recommended for review. Notably, if no provider is registered, the API returns the provided default rather than failing, so an unreachable provider results in graceful degradation. Additionally, hooks execute in a stack-wise manner, enabling a single global before-hook to assemble tenant context for all call sites. The trade-off is the need to understand and maintain an additional layer.
The true measure of whether this separation was valuable is not improved reliability, but the cost of changing providers in the future.
What it costs
Self-hosting shifts operational responsibility in-house. This is beneficial when a platform team has established conventions, but costly without them, as the value depends on existing discipline. Maintenance becomes an ongoing process. Without regular upkeep, a fixed vocabulary can become outdated and misleading.
Cache keys must include all attributes referenced by targeting rules to prevent serving one tenant’s resolution to another tenant.
During migration, two evaluation paths coexist, making the overall evaluation more complex than either alone. Any incremental migration introduces a period where a flag may be interpreted in two ways, trading temporary complexity for a safer transition.
When not to do this
If you have a single provider, few flags, and no foreseeable need for change, abstraction adds unnecessary overhead. It is justified when flags are critical, the rollout subject is not an individual user, or provider failures have already impacted users. Otherwise, maintain a simpler approach to avoid unnecessary complexity.
Reference. OpenFeature specification · providers · hooks