OpenFeature JavaScript SDKs
repository·main·Indexed 43 days ago
https://github.com/open-feature/js-sdkVendor-agnostic API for feature flagging in JavaScript. Includes specialized SDKs for Angular (supporting version 16+ with structural directives and FeatureFlagService) and NestJS (supporting version 8+ and Node.js 20+), allowing developers to integrate various feature flag providers without vendor lock-in.
What's inside OpenFeature
- OpenFeature is an open standard that provides a vendor-agnostic, community-driven API for feature flagging. It allows you to use your favorite feature flag management tools through a unified interface, which prevents vendor lock-in at the code level. By standardizing the interface, developers can switch providers without rewriting their application logic, and providers can focus on their unique features while remaining compatible with the standard.
Overview of OpenFeature React SDK
mainThe OpenFeature React SDK extends the capabilities of the OpenFeature Web SDK by adding React-specific features. It allows you to integrate vendor-agnostic feature flagging directly into your React component tree using context providers, hooks, and declarative components.Best practices for library developers using OpenFeature
mainIf you are developing a library that depends on OpenFeature components, you should list
@openfeature/server-sdkas apeerDependencyin yourpackage.json.Why this is important:
- Avoid Multiple Instances: It prevents the consumer from having multiple copies of the OpenFeature SDK, which can break singleton behavior.
- Type Safety: It ensures that types remain consistent across the application.
- Transitive Dependencies: You do not need to explicitly add
@openfeature/coreas a peer dependency, because@openfeature/server-sdkalready handles that dependency transitively.
Use OpenFeatureProvider context provider
mainThe
OpenFeatureProvideris a React context provider that represents a scope for feature flag evaluations. It binds an OpenFeature client to all evaluations within child components and enables the use of evaluation hooks.Note:
OpenFeature.setProvider()should only be called once. You do not need to await its initialization; the React SDK handles re-rendering and suspense automatically.import { EvaluationContext, OpenFeatureProvider, useFlag, OpenFeature, TypedInMemoryProvider, } from '@openfeature/react-sdk'; const flagConfig = { 'new-message': { disabled: false, variants: { on: true, off: false, }, defaultVariant: 'on', contextEvaluator: (context: EvaluationContext) => { if (context.silly) { return 'on'; } return 'off'; }, }, } as const; // Instantiate and set our provider (be sure this only happens once)! OpenFeature.setProvider(new TypedInMemoryProvider(flagConfig)); // Enclose your content in the configured provider function App() { return ( <OpenFeatureProvider> <Page></Page> </OpenFeatureProvider> ); }Configure flag evaluation context injection
mainTo trigger specific evaluation rules (e.g., based on user email or role), you can inject evaluation context into every flag evaluation for a request.
Use the
contextFactoryoption inOpenFeatureModule.forRoot()to define how context is built. This factory runs within a NestJS interceptor scope.By default, the interceptor is global. If you set
useGlobalInterceptor: falsein the module configuration, you can manually inject thecontextFactoryinto route, module, or controller-bound interceptors.Scope OpenFeatureProvider using the domain parameter
mainBy default,
OpenFeatureProviderbinds a client to all child components, but the underlying provider/context is controlled by thedomainparameter. To ensure anOpenFeatureProvideris scoped to a specific provider or context, set thedomainprop.<OpenFeatureProvider domain={'my-domain'> <Page /> </OpenFeatureProvider>Choose the right OpenFeature SDK for your environment
mainThe OpenFeature JavaScript SDKs are split into different packages depending on your runtime and framework. While they share many underlying types and components, their APIs may vary slightly to suit their specific environments.
Server-side (Node.js and similar runtimes)
- Server SDK: The core SDK for server-side environments.
- NestJS SDK: A distribution of the Server SDK specifically optimized with built-in features for NestJS applications.
Client-side (Web Browser)
- Web SDK: The core SDK for use in web browsers.
- React SDK: A distribution of the Web SDK specifically optimized with built-in features for React applications.
Which OpenFeature packages to import in Angular
mainWhen working in an Angular project, you should import everything directly from
@openfeature/angular-sdk.While
@openfeature/angular-sdkre-exports everything from its peer dependencies (@openfeature/web-sdkand@openfeature/core) and adds Angular-specific features, you should avoid importing directly from@openfeature/web-sdkor@openfeature/coreto ensure compatibility and proper integration with the Angular SDK.Implement Targeting with Evaluation Context
mainTargeting allows flag evaluation to consider dynamic criteria like user ID, location, or IP address. You provide this data using an evaluation context. The SDK merges context from three levels:
- Global Context: Set via
OpenFeature.setContext(). - Client Context: Set via
client.setContext(). - Invocation Context: Passed directly to the flag evaluation method (e.g.,
getBooleanValue).
Context is merged by the SDK before evaluation occurs according to the OpenFeature specification.
// Global context OpenFeature.setContext({ region: 'us-east-1' }); // Client context const client = OpenFeature.getClient(); client.setContext({ version: process.env.APP_VERSION }); // Invocation context const requestContext = { targetingKey: req.session.id, email: req.session.email, product: req.productId, }; const boolValue = await client.getBooleanValue('some-flag', false, requestContext);- Global Context: Set via
Use Domains to associate clients with specific providers
mainA domain is a logical identifier used to bind specific clients to specific providers. If a client requests a domain that has no associated provider, it will fall back to the default provider.
- Registering a provider to a domain:
OpenFeature.setProvider('my-domain', provider) - Getting a domain-scoped client:
OpenFeature.getClient('my-domain') - Clearing context: Use
OpenFeature.clearContext('my-domain')to clear a specific domain's context, orOpenFeature.clearContexts()to reset everything.
import { OpenFeature, TypedInMemoryProvider } from '@openfeature/web-sdk'; const myFlags = { /* ... flag definitions ... */ } as const; // Registering the default provider OpenFeature.setProvider(new TypedInMemoryProvider(myFlags)); // Registering a provider to a specific domain OpenFeature.setProvider('my-domain', new TypedInMemoryProvider(someOtherFlags)); // A Client bound to the default provider const clientWithDefault = OpenFeature.getClient(); // A Client bound to the 'my-domain' provider const domainScopedClient = OpenFeature.getClient('my-domain');- Registering a provider to a domain:
Use Multi-Provider to combine multiple flag sources
mainThe
MultiProviderallows you to manage multiple underlying providers as a single source of truth. This is useful for migrations (falling back from a new provider to an old one) or combining different data sources (e.g., environment variables + SaaS).By default, it uses the
FirstMatchStrategy, which returns the first successful result and skips providers that return aFLAG_NOT_FOUNDerror.Evaluation Strategies
FirstMatchStrategy(default): Returns the first successful result. Skips providers returningFLAG_NOT_FOUND.FirstSuccessfulStrategy: Returns the first successful result. Any error (not justFLAG_NOT_FOUND) causes the provider to be skipped.ComparisonStrategy: Evaluates all providers. If all successful providers return the same value, that value is returned. Otherwise, it returns the value from a configured "fallback provider".
import { MultiProvider, FirstSuccessfulStrategy } from '@openfeature/web-sdk'; // Example: Using FirstSuccessfulStrategy const multiProvider = new MultiProvider( [{ provider: new ProviderA() }, { provider: new ProviderB() }], new FirstSuccessfulStrategy(), ); await OpenFeature.setProviderAndWait(multiProvider); const client = OpenFeature.getClient(); console.log(client.getBooleanDetails('my-flag', false));Handle tracking events with Multi-Provider
mainThe
MultiProvidersupports tracking events across multiple providers. When you callclient.track(...), the event is sent to all underlying providers that implement thetrackmethod.Default Behavior:
- All providers receive tracking calls.
- If one provider fails to track, others continue and errors are logged.
- Providers in
NOT_READYorFATALstatus are automatically skipped. - Providers without a
trackmethod are gracefully skipped.
import { OpenFeature } from '@openfeature/server-sdk'; import { MultiProvider } from '@openfeature/server-sdk'; const multiProvider = new MultiProvider([{ provider: new ProviderA() }, { provider: new ProviderB() }]); await OpenFeature.setProviderAndWait(multiProvider); const client = OpenFeature.getClient(); // Tracked events are sent to all providers by default client.track('purchase', { targetingKey: 'user123' }, { value: 99.99, currency: 'USD' });