Why OpenFeature Matters: Breaking Free from Vendor Lock-In
Most feature flag platforms trap you with proprietary SDKs — switching means rewriting every evaluation call across your entire codebase. OpenFeature changes that. We shipped native OpenFeature providers across all 8 of our SDKs, so you can swap from LaunchDarkly to FeatureSignals with a one-line provider change. Here's the architecture, code examples in Go, Node, and Python, and the case for open standards in developer tooling.
The Vendor Lock-In Problem
Every feature flag platform ships its own SDK. LaunchDarkly has `launchdarkly-server-sdk`. Split has `splitio`. Flagsmith has `flagsmith`. Each SDK comes with its own initialization, its own evaluation API, its own context model, and its own idioms. Once you've instrumented your codebase with one vendor's SDK, switching vendors isn't a configuration change — it's a rewrite. Every `client.variation('flag-key', user, false)` call across every service, every test mock, every deployment script has to change.
This lock-in isn't accidental. It's a business model. The harder it is to leave, the more the vendor can raise prices, degrade service, or deprecate features without losing customers. We've heard from teams paying $50,000+/year for feature flags with evaluation latencies in the hundreds of milliseconds, wanting to switch but unable to justify the engineering cost of rewriting thousands of evaluation calls.
What OpenFeature Is
OpenFeature is a CNCF project that defines a vendor-neutral API for feature flag evaluation. It specifies a standard interface — `getBooleanValue`, `getStringValue`, `getNumberValue`, `getObjectValue` — that any feature flag provider implements. Your application code calls the OpenFeature API. Behind that API, a provider handles the actual evaluation logic. To switch vendors, you change the provider, not your code.
The standard is deliberately minimal. It doesn't try to cover flag management, user segmentation, or analytics. It focuses on one thing: evaluating a flag for a given context and returning a typed result with resolution metadata. This narrow scope makes the standard implementable across every language ecosystem and compatible with every feature flag back end.
How FeatureSignals Implements OpenFeature
FeatureSignals provides OpenFeature providers for all 8 of our supported languages: Go, Node.js, Python, Java, .NET, Ruby, PHP, and Rust. Each provider wraps the FeatureSignals evaluation engine and translates the OpenFeature evaluation context into the format our engine expects. The provider also handles connection management, caching, and error handling — so your application code never needs to know anything about FeatureSignals internals.
// Go: One-line provider swap — LaunchDarkly to FeatureSignals
import (
"github.com/open-feature/go-sdk/openfeature"
fsprovider "github.com/featuresignals/openfeature-provider-go"
)
func main() {
// Before: LaunchDarkly
// client := ldclient.MakeClient("sdk-key-xxx", 5*time.Second)
// After: FeatureSignals (drop-in replacement)
provider := fsprovider.NewProvider(
fsprovider.WithAPIKey(os.Getenv("FS_API_KEY")),
)
openfeature.SetProvider(provider)
client := openfeature.NewClient("my-app")
// All evaluation calls unchanged — same OpenFeature API
enabled, _ := client.BooleanValue(
context.Background(),
"new-checkout",
false,
openfeature.NewEvaluationContext("user-123",
map[string]interface{}{
"email": "user@example.com",
},
),
)
}// Node.js: Initialize once, evaluate everywhere
import { OpenFeature } from '@openfeature/js-sdk';
import { FeatureSignalsProvider } from '@featuresignals/openfeature-provider-node';
// One-time setup — typically in your app's entry point
OpenFeature.setProvider(
new FeatureSignalsProvider({
apiKey: process.env.FS_API_KEY,
}),
);
const client = OpenFeature.getClient();
// Anywhere in your application — same API regardless of vendor
const useNewUI = await client.getBooleanValue(
'new-dashboard',
false,
{
targetingKey: 'user-456',
email: 'user@example.com',
plan: 'enterprise',
},
);
if (useNewUI) {
renderNewDashboard();
}# Python: OpenFeature with FeatureSignals provider
from openfeature import api
from openfeature.contrib.provider.featuresignals import FeatureSignalsProvider
# Initialize once at application startup
provider = FeatureSignalsProvider(api_key="fs_api_xxx")
api.set_provider(provider)
client = api.get_client()
# Evaluate anywhere — clean, typed, vendor-neutral
ctx = api.EvaluationContext(
targeting_key="user-789",
attributes={
"email": "user@example.com",
"region": "us-east-1",
},
)
use_ml_ranking = client.get_boolean_value(
"ml-ranking-v2",
default_value=False,
evaluation_context=ctx,
)
if use_ml_ranking:
serve_ml_results()The Evaluation Context
The OpenFeature evaluation context is the mechanism by which targeting attributes flow from your application to the evaluation engine. It's a flat key-value structure with a special `targetingKey` field that identifies the subject of evaluation (usually a user ID). Everything else — email, plan, region, beta status, team — is an attribute that can be referenced in targeting rules.
FeatureSignals enriches this context with server-side attributes (IP geolocation, request headers, timezone) before evaluation, so you don't need to manually propagate attributes that the platform can derive automatically. This enrichment happens inside the provider, transparently to your application code.
Resolution Details: Understanding Why
Every OpenFeature evaluation returns not just a value but a `ResolutionDetails` object that explains why the flag resolved the way it did. This is critical for debugging: is a user receiving the default variation because they're not targeted, or because the flag is disabled, or because of an error?
// ResolutionDetails tells you the full story of an evaluation
details := client.BooleanValueDetails(
ctx, "premium-feature", false, evalCtx,
)
fmt.Printf("Value: %v\n", details.Value) // true or false
fmt.Printf("Reason: %s\n", details.Reason) // TARGETED, DEFAULT, SPLIT, ERROR
fmt.Printf("Variant: %s\n", details.Variant) // "premium-v1", "control"
fmt.Printf("Flag: %s\n", details.FlagKey) // "premium-feature"
// Reason codes are standardized across all OpenFeature providers:
// - STATIC: Flag resolved to a static/unchanging value
// - TARGETED: User was individually targeted
// - SPLIT: User fell into a percentage rollout bucket
// - DEFAULT: No rules matched, serving default
// - ERROR: Evaluation failed, serving fallback valueThe Business Case for Open Standards
Adopting OpenFeature isn't just a technical decision — it's a strategic one. It de-risks your feature flag infrastructure by decoupling your application code from any specific vendor. If your current vendor raises prices, has an outage, or discontinues a feature you depend on, you can switch without rewriting your codebase. It also simplifies multi-vendor scenarios: you might use FeatureSignals for server-side flags and a different provider for client-side experimentation, all through the same OpenFeature API.
For teams evaluating feature flag platforms, OpenFeature support should be a hard requirement. A platform that doesn't support OpenFeature is explicitly choosing to lock you in. A platform that does support it is competing on the quality of its evaluation engine, its management UI, and its additional capabilities — not on the switching cost.
Info
FeatureSignals is a founding contributor to the OpenFeature standard. All our SDKs implement the OpenFeature specification natively. You can use the FeatureSignals provider, or write your own provider against our evaluation API — both paths are fully supported and documented.
What This Means for Your Architecture
If you're starting a new project today, instrument it with OpenFeature from day one. Even if you're using FeatureSignals as your back end, the OpenFeature abstraction costs you nothing and gives you optionality. If you're maintaining an existing project with a proprietary SDK, plan a gradual migration: wrap the proprietary SDK behind an OpenFeature-compatible provider, then swap the provider when ready. The wrapper is typically 50–100 lines of code and can be tested in isolation.
Open standards in developer tooling are inevitable. We saw it with observability (OpenTelemetry), with CI/CD (GitHub Actions workflow syntax becoming a de facto standard), and with container orchestration (Kubernetes). Feature flagging is next. OpenFeature is the standard, and we're proud to build on it.