OpenFeature Angular SDK
npm install @openfeature/angular-sdk
OpenFeature is an open specification that provides a vendor-agnostic, community-driven API
for feature flagging that works with your favorite feature flag management tool or in-house solution.
The OpenFeature Angular SDK adds Angular-specific functionality to
the OpenFeature Web SDK.
In addition to the features provided by the web sdk, capabilities include:
- Overview
- Quick start
- Requirements
- Install
- npm
- yarn
- Required peer dependencies
- Usage
- Module
- Minimal Example
- How to use
- Structural Directives
- Boolean Feature Flag
- Number Feature Flag
- String Feature Flag
- Object Feature Flag
- Opting-out of automatic re-rendering
- Consuming the evaluation details
- FeatureFlagService
- Using with Observables
- Using with Angular Signals
- Service Options
- Setting evaluation context
- Using a static object
- Using a factory function
- Observability considerations
- FAQ and troubleshooting
- Resources
- ES2015-compatible web browser (Chrome, Edge, Firefox, etc)
- Angular version 16+
#### npm
``sh`
npm install --save @openfeature/angular-sdk
#### yarn
`sh`yarn requires manual installation of the peer dependencies (see below)
yarn add @openfeature/angular-sdk @openfeature/web-sdk @openfeature/core
#### Required peer dependencies
The following list contains the peer dependencies of @openfeature/angular-sdk.
See the package.json for the required versions.
- @openfeature/web-sdk@angular/common
- @angular/core
-
#### Module
To include the OpenFeature Angular directives in your application, you need to import the OpenFeatureModule andforRoot
configure it using the method.
`typescript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { OpenFeatureModule } from '@openfeature/angular-sdk';
@NgModule({
declarations: [
// Other components
],
imports: [
CommonModule,
OpenFeatureModule.forRoot({
provider: yourFeatureProvider,
// domainBoundProviders are optional, mostly needed if more than one provider is used in the application.
domainBoundProviders: {
domain1: new YourOpenFeatureProvider(),
domain2: new YourOtherOpenFeatureProvider(),
},
}),
],
})
export class AppModule {}
`
##### Minimal Example
You don't need to provide all the templates. Here's a minimal example using a boolean feature flag:
If initializing and reconciling are not given, the feature flag value that is returned by the provider will
determine what will be rendered.
`html`This is shown when the feature flag is enabled.
This example shows content when the feature flag isFeatureEnabled is true with a default value of true.else
No , initializing, or reconciling templates are required in this case.
#### How to use
The library provides two main ways to work with feature flags:
1. Structural Directives - For template-based conditional rendering
2. FeatureFlagService - For programmatic access with Observables
##### Structural Directives
The library provides four primary directives for feature flags, booleanFeatureFlag,numberFeatureFlag, stringFeatureFlag and objectFeatureFlag.
The first value given to the directive is the flag key that should be evaluated.
For all directives, the default value passed to OpenFeature has to be provided by the default parameter.
For all non-boolean directives, the value to compare the evaluation result to can be provided by the value parameter.thenTemplate
This parameter is optional, if omitted, the will always be rendered.
The domain parameter is _optional_ and will be used as domain when getting the OpenFeature provider.
The updateOnConfigurationChanged and updateOnContextChanged parameter are _optional_ and used to disable thetrue
automatic re-rendering on flag value or context change. They are set to by default.
The template referenced in else will be rendered if the evaluated feature flag is false for the booleanFeatureFlagvalue
directive and if the does not match evaluated flag value for all other directives.
This parameter is _optional_.
The template referenced in initializing and reconciling will be rendered if OpenFeature provider is in thethen
corresponding states.
This parameter is _optional_, if omitted, the and else templates will be rendered according to the flag value.
###### Boolean Feature Flag
`html
*booleanFeatureFlag="'isFeatureEnabled'; default: true; domain: 'userDomain'; else: booleanFeatureElse; initializing: booleanFeatureInitializing; reconciling: booleanFeatureReconciling"
>
This is shown when the feature flag is enabled.
###### Number Feature Flag
`html
*numberFeatureFlag="'discountRate'; value: 10; default: 5; domain: 'userDomain'; else: numberFeatureElse; initializing: numberFeatureInitializing; reconciling: numberFeatureReconciling"
>
This is shown when the feature flag matches the specified discount rate.
###### String Feature Flag
`html
*stringFeatureFlag="'themeColor'; value: 'dark'; default: 'light'; domain: 'userDomain'; else: stringFeatureElse; initializing: stringFeatureInitializing; reconciling: stringFeatureReconciling"
>
This is shown when the feature flag matches the specified theme color.
###### Object Feature Flag
`html
*objectFeatureFlag="'userConfig'; value: { theme: 'dark' }; default: { theme: 'light' }; domain: 'userDomain'; else: objectFeatureElse; initializing: objectFeatureInitializing; reconciling: objectFeatureReconciling"
>
This is shown when the feature flag matches the specified user configuration.
###### Opting-out of automatic re-rendering
By default, the directive re-renders when the flag value changes or the context changes.
In cases, this is not desired, re-rendering can be disabled for both events:
`html
*booleanFeatureFlag="'isFeatureEnabled'; default: true; updateOnContextChanged: false; updateOnConfigurationChanged: false;"
>
This is shown when the feature flag is enabled.
###### Consuming the evaluation details
The
evaluation details can be used when rendering the templates.
The directives $implicit
value will be bound to the flag value and additionally the value evaluationDetails will be
bound to the whole evaluation details.
They can be referenced in all templates.The following example shows
value being implicitly bound and details being bound to the evaluation details.`html
*stringFeatureFlag="'themeColor'; value: 'dark'; default: 'light'; else: stringFeatureElse; let value; let details = evaluationDetails"
>
It was a match! The theme color is {{ value }} because of {{ details.reason }}
When the expected flag value is omitted, the template will always be rendered.
This can be used to just render the flag value or details without conditional rendering.
`html
The theme color is {{ value }}.
`##### FeatureFlagService
The
FeatureFlagService provides programmatic access to feature flags through reactive patterns. All methods return
Observables that automatically emit new values when flag configurations or evaluation context changes.###### Using with Observables
`typescript
import { Component, inject } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { FeatureFlagService } from '@openfeature/angular-sdk';@Component({
selector: 'my-component',
standalone: true,
imports: [AsyncPipe],
template:
,
})
export class MyComponent {
private flagService = inject(FeatureFlagService); // Boolean flag
isFeatureEnabled$ = this.flagService.getBooleanDetails('my-feature', false);
// String flag
currentTheme$ = this.flagService.getStringDetails('theme', 'light');
// Number flag
maxItems$ = this.flagService.getNumberDetails('max-items', 10);
// Object flag with type safety
config$ = this.flagService.getObjectDetails<{ timeout: number }>('api-config', { timeout: 5000 });
}
`###### Using with Angular Signals
You can convert any Observable from the service to an Angular Signal using
toSignal():`typescript
import { Component, inject } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { FeatureFlagService } from '@openfeature/angular-sdk';@Component({
selector: 'my-component',
standalone: true,
template:
,
})
export class MyComponent {
private flagService = inject(FeatureFlagService); // Convert Observables to Signals
isFeatureEnabled = toSignal(this.flagService.getBooleanDetails('my-feature', false));
currentTheme = toSignal(this.flagService.getStringDetails('theme', 'light'));
}
`###### Service Options
The service methods accept the same options as the directives:
`typescript
const flag$ = this.flagService.getBooleanDetails('my-flag', false, 'my-domain', {
updateOnConfigurationChanged: false, // default: true
updateOnContextChanged: false, // default: true
});
`##### Setting evaluation context
To set the initial evaluation context, you can add the
context parameter to the OpenFeatureModule configuration.
This context can be either an object or a factory function that returns an EvaluationContext.> [!TIP]
> Updating the context can be done directly via the global OpenFeature API using
OpenFeature.setContext()Here’s how you can define and use the initial client evaluation context:
###### Using a static object
`typescript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { OpenFeatureModule } from '@openfeature/angular-sdk';const initialContext = {
user: {
id: 'user123',
role: 'admin',
},
};
@NgModule({
imports: [
CommonModule,
OpenFeatureModule.forRoot({
provider: yourFeatureProvider,
context: initialContext,
}),
],
})
export class AppModule {}
`###### Using a factory function
`typescript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { OpenFeatureModule, EvaluationContext } from '@openfeature/angular-sdk';const contextFactory = (): EvaluationContext => loadContextFromLocalStorage();
@NgModule({
imports: [
CommonModule,
OpenFeatureModule.forRoot({
provider: yourFeatureProvider,
context: contextFactory,
}),
],
})
export class AppModule {}
`##### Observability considerations
Angular's lifecycle can result in flags being evaluated multiple times as a user interacts with a page.
If you are using an OpenFeature hook for telemetry, this can result in inflated evaluation metrics.
The OpenFeature debounce hook can help
to reduce the amount of redundant evaluations reported to your observability platform by limiting the frequency at which
evaluation metrics are reported.
FAQ and troubleshooting
> I can import things form the
@openfeature/angular-sdk, @openfeature/web-sdk, and @openfeature/core; which should I use?The
@openfeature/angular-sdk re-exports everything from its peers (@openfeature/web-sdk and @openfeature/core),
and adds the Angular-specific features.
You can import everything from the @openfeature/angular-sdk directly.
Avoid importing anything from @openfeature/web-sdk or @openfeature/core`.