Feature flags for Angular — services, directives, and route guards
Sign up at flagbit.anethoth.com to get your SDK key. The free tier includes 1,000 evaluations/day.
ng generate service feature-flag
// feature-flag.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { map, catchError, shareReplay } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class FeatureFlagService {
private cache = new Map<string, Observable<boolean>>();
private sdkKey = environment.flagbitSdkKey;
constructor(private http: HttpClient) {}
isEnabled(flagKey: string, context: Record<string, string> = {}): Observable<boolean> {
const cacheKey = `${flagKey}:${JSON.stringify(context)}`;
if (!this.cache.has(cacheKey)) {
this.cache.set(cacheKey,
this.http.post<{value: boolean}>(
'https://flagbit.anethoth.com/api/v1/evaluate',
{ flag_key: flagKey, context },
{ headers: { 'X-SDK-Key': this.sdkKey } }
).pipe(
map(r => r.value),
catchError(() => of(false)),
shareReplay(1)
)
);
}
return this.cache.get(cacheKey)!;
}
}
// Structural directive — *featureFlag="'new-sidebar'"
@Directive({ selector: '[featureFlag]' })
export class FeatureFlagDirective implements OnInit {
@Input() featureFlag!: string;
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private flags: FeatureFlagService
) {}
ngOnInit() {
this.flags.isEnabled(this.featureFlag).subscribe(enabled => {
this.viewContainer.clear();
if (enabled) this.viewContainer.createEmbeddedView(this.templateRef);
});
}
}
// Route guard
@Injectable({ providedIn: 'root' })
export class FeatureGuard implements CanActivate {
constructor(private flags: FeatureFlagService) {}
canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
const flagKey = route.data['featureFlag'];
return this.flags.isEnabled(flagKey);
}
}
// Route config
{ path: 'beta', component: BetaComponent, canActivate: [FeatureGuard],
data: { featureFlag: 'beta-section' } }
// Template: <div *featureFlag="'new-widget'">New widget here</div>
Gate lazy-loaded Angular modules behind feature flags — only load code users are allowed to see.
Show different component implementations based on flags using structural directives.
Protect entire routes with feature flag guards — unauthorized users see a 404.
Inject different service implementations based on feature flags using factory providers.
Define flags in your FlagBit dashboard with targeting rules and rollout percentages.
Call the evaluate endpoint from your Angular app with user context for targeted rollouts.
Enable, disable, or adjust rollouts in real-time. No redeployment needed.
Yes — in Angular 16+, convert the Observable to a signal using toSignal() for reactive flag values.
Provide a mock FeatureFlagService in TestBed that returns of(true) or of(false).
Yes — the HTTP call works server-side. Use TransferState to avoid re-fetching on the client.
Yes — inject FeatureFlagService directly. The structural directive works with standalone too.
Free tier includes 1 project, 10 flags, and 1,000 evaluations/day. No credit card required.
Get Your Free API Key