NestJS
Use Flipswitch feature flags in NestJS with dependency injection and guards
The OpenFeature NestJS SDK provides NestJS-specific decorators and modules on top of the Flipswitch server provider. Flags evaluate server-side with real-time SSE updates.
See the JavaScript SDK for full provider configuration (polling fallback, reconnection, etc.).
Requirements
- Node.js 20+
- NestJS 8+
Installation
npm install @flipswitch-io/server-provider @openfeature/nestjs-sdkyarn add @flipswitch-io/server-provider @openfeature/nestjs-sdkpnpm add @flipswitch-io/server-provider @openfeature/nestjs-sdk@openfeature/nestjs-sdk re-exports everything from @openfeature/server-sdk. Import all OpenFeature types from @openfeature/nestjs-sdk directly.
Quick Start
Module Setup
import { Module } from '@nestjs/common';
import { OpenFeatureModule } from '@openfeature/nestjs-sdk';
import { FlipswitchServerProvider } from '@flipswitch-io/server-provider';
@Module({
imports: [
OpenFeatureModule.forRoot({
defaultProvider: new FlipswitchServerProvider({
apiKey: 'YOUR_API_KEY',
}),
}),
],
})
export class AppModule {}Using in a Controller
import { Controller, Get } from '@nestjs/common';
import { OpenFeatureClient, Client } from '@openfeature/nestjs-sdk';
@Controller()
export class AppController {
constructor(
@OpenFeatureClient() private client: Client,
) {}
@Get('/feature')
async checkFeature() {
const enabled = await this.client.getBooleanValue('new-feature', false);
return { featureEnabled: enabled };
}
}Client Injection
Use the @OpenFeatureClient() decorator to inject the OpenFeature client into any service or controller:
import { Injectable } from '@nestjs/common';
import { OpenFeatureClient, Client } from '@openfeature/nestjs-sdk';
@Injectable()
export class FeatureService {
constructor(
@OpenFeatureClient() private client: Client,
) {}
async isEnabled(flagKey: string, userId: string): Promise<boolean> {
return this.client.getBooleanValue(flagKey, false, {
targetingKey: userId,
});
}
}Domain-Scoped Clients
Use multiple providers for different domains:
@Module({
imports: [
OpenFeatureModule.forRoot({
defaultProvider: new FlipswitchServerProvider({ apiKey: 'DEFAULT_KEY' }),
providers: {
billing: new FlipswitchServerProvider({ apiKey: 'BILLING_KEY' }),
},
}),
],
})
export class AppModule {}Inject a domain-scoped client:
@Injectable()
export class BillingService {
constructor(
@OpenFeatureClient({ domain: 'billing' }) private client: Client,
) {}
}Flag Parameter Decorators
Inject flag values directly into route handler parameters as Observables:
import { Controller, Get } from '@nestjs/common';
import { map, Observable } from 'rxjs';
import { BooleanFeatureFlag, EvaluationDetails } from '@openfeature/nestjs-sdk';
@Controller()
export class AppController {
@Get('/welcome')
welcome(
@BooleanFeatureFlag({ flagKey: 'new-welcome', defaultValue: false })
flag: Observable<EvaluationDetails<boolean>>,
) {
return flag.pipe(
map((details) =>
details.value
? { message: 'Welcome to the new experience!' }
: { message: 'Welcome!' }
),
);
}
}Available decorators:
@BooleanFeatureFlag({ flagKey: 'flag', defaultValue: false })
@StringFeatureFlag({ flagKey: 'flag', defaultValue: 'default' })
@NumberFeatureFlag({ flagKey: 'flag', defaultValue: 0 })
@ObjectFeatureFlag({ flagKey: 'flag', defaultValue: {} })RequireFlagsEnabled Guard
Block access to routes when flags are disabled. Returns a 404 by default when any specified flag evaluates to false:
import { Controller, Get } from '@nestjs/common';
import { RequireFlagsEnabled } from '@openfeature/nestjs-sdk';
@Controller('beta')
export class BetaController {
@Get()
@RequireFlagsEnabled({
flags: [{ flagKey: 'beta-access' }],
})
getBetaContent() {
return { content: 'Beta feature content' };
}
}Custom Exception
import { ForbiddenException } from '@nestjs/common';
@RequireFlagsEnabled({
flags: [
{ flagKey: 'premium-feature' },
{ flagKey: 'feature-v2', defaultValue: true },
],
exception: new ForbiddenException('Feature not available'),
})With Context
import { RequireFlagsEnabled } from '@openfeature/nestjs-sdk';
@RequireFlagsEnabled({
flags: [{ flagKey: 'premium-feature' }],
contextFactory: (executionContext) => {
const request = executionContext.switchToHttp().getRequest();
return {
targetingKey: request.user?.id,
plan: request.user?.plan,
};
},
})Apply at the class level to gate an entire controller:
@Controller('experimental')
@RequireFlagsEnabled({
flags: [{ flagKey: 'experimental-api' }],
})
export class ExperimentalController {
// All routes require 'experimental-api' to be enabled
}Evaluation Context
Per-Request Context
The module registers a global interceptor by default that propagates evaluation context through the request lifecycle. Provide a contextFactory to extract context from each request:
OpenFeatureModule.forRoot({
defaultProvider: new FlipswitchServerProvider({ apiKey: 'YOUR_API_KEY' }),
contextFactory: (executionContext) => {
const request = executionContext.switchToHttp().getRequest();
return {
targetingKey: request.user?.id,
email: request.user?.email,
plan: request.user?.plan,
};
},
})Static Context
For context that doesn't change per request:
OpenFeatureModule.forRoot({
defaultProvider: new FlipswitchServerProvider({ apiKey: 'YOUR_API_KEY' }),
context: {
environment: 'production',
region: 'eu-west-1',
},
})Disabling the Global Interceptor
If you prefer to set context manually, disable the global interceptor:
OpenFeatureModule.forRoot({
defaultProvider: new FlipswitchServerProvider({ apiKey: 'YOUR_API_KEY' }),
useGlobalInterceptor: false,
})Real-Time Updates
The Flipswitch server provider maintains an SSE connection for instant flag updates. No additional NestJS configuration is needed. The provider is automatically shut down when the NestJS application stops.
Configuration Reference
OpenFeatureModule.forRoot() accepts:
| Option | Type | Default | Description |
|---|---|---|---|
defaultProvider | Provider | - | The default OpenFeature provider |
providers | Record<string, Provider> | - | Domain-scoped providers |
context | EvaluationContext | - | Static evaluation context |
contextFactory | (ctx: ExecutionContext) => EvaluationContext | - | Per-request context factory |
useGlobalInterceptor | boolean | true | Register context interceptor globally |
hooks | Hook[] | - | OpenFeature hooks |
handlers | [ServerProviderEvents, EventHandler][] | - | Event handlers |
logger | Logger | - | Custom logger |