npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@flagify/nestjs

v1.0.5

Published

NestJS integration for Flagify — module, service, guards, and decorators for feature flag evaluation.

Readme


Overview

@flagify/nestjs is the official NestJS integration for Flagify. A full-featured module with service, guard, and decorators for feature flag evaluation in NestJS applications.

  • NestJS-native -- Dynamic module with forRoot / forRootAsync registration
  • Injectable service -- FlagifyService with isEnabled, getValue, getVariant, and evaluate
  • Route guard -- FeatureFlagGuard + @RequireFlag() decorator to gate endpoints
  • Param decorator -- @FeatureFlag() to inject flag values into route handlers
  • User targeting -- identify callback for per-request evaluation with targeting rules
  • Testing module -- FlagifyTestingModule.withFlags() for unit tests without HTTP calls
  • TypeScript-first -- Full type safety with generics

Table of contents

Installation

# pnpm
pnpm add @flagify/nestjs

# npm
npm install @flagify/nestjs

# yarn
yarn add @flagify/nestjs

Peer dependencies: @nestjs/common >= 10, @nestjs/core >= 10, reflect-metadata >= 0.1.13

Quick start

1. Register the module

import { Module } from '@nestjs/common'
import { FlagifyModule } from '@flagify/nestjs'

@Module({
  imports: [
    FlagifyModule.forRoot({
      projectKey: 'proj_xxx',
      publicKey: 'pk_xxx',
    }),
  ],
})
export class AppModule {}

2. Inject the service

import { Injectable } from '@nestjs/common'
import { FlagifyService } from '@flagify/nestjs'

@Injectable()
export class PaymentService {
  constructor(private readonly flagify: FlagifyService) {}

  checkout() {
    if (this.flagify.isEnabled('new-checkout')) {
      return this.newCheckout()
    }
    return this.legacyCheckout()
  }
}

3. Gate a route with a decorator

import { Controller, Get, UseGuards } from '@nestjs/common'
import { FeatureFlagGuard, RequireFlag } from '@flagify/nestjs'

@Controller('experiments')
@UseGuards(FeatureFlagGuard)
export class ExperimentsController {
  @Get()
  @RequireFlag('experiments-enabled')
  getExperiments() {
    return { experiments: [] }
  }
}

Module registration

FlagifyModule.forRoot(options)

Synchronous registration. The module is global by default (isGlobal: true).

FlagifyModule.forRoot({
  projectKey: 'proj_xxx',
  publicKey: 'pk_xxx',
  secretKey: 'sk_xxx',
  isGlobal: true,
  identify: (context) => {
    const request = context.switchToHttp().getRequest()
    return { id: request.user.id, email: request.user.email }
  },
  options: {
    apiUrl: 'https://api.flagify.dev',
    staleTimeMs: 300_000,
  },
})

FlagifyModule.forRootAsync(asyncOptions)

Async registration for when options depend on other providers (e.g. ConfigService).

FlagifyModule.forRootAsync({
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: (config: ConfigService) => ({
    projectKey: config.get('FLAGIFY_PROJECT_KEY'),
    publicKey: config.get('FLAGIFY_PUBLIC_KEY'),
    secretKey: config.get('FLAGIFY_SECRET_KEY'),
    identify: (context) => {
      const req = context.switchToHttp().getRequest()
      return { id: req.user.id }
    },
  }),
})

Options

| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | projectKey | string | Yes | -- | Project identifier from your Flagify workspace | | publicKey | string | Yes | -- | Client-safe publishable API key | | secretKey | string | No | -- | Server-side secret key | | isGlobal | boolean | No | true | Register the module globally | | identify | (context: ExecutionContext) => FlagifyUser | No | -- | Extract user context from requests for targeting | | options | object | No | -- | Additional config (apiUrl, staleTimeMs, realtime, user) |

Service

FlagifyService

Injectable service that wraps the @flagify/node client. Initializes on module init and destroys on module destroy.

import { FlagifyService } from '@flagify/nestjs'

@Injectable()
export class MyService {
  constructor(private readonly flagify: FlagifyService) {}
}

Methods


isReady(): boolean

Returns true once the client has completed its initial flag sync.


isEnabled(flagKey: string): boolean

Evaluates a boolean feature flag. Returns false if the flag doesn't exist, is disabled, or is not a boolean type.

if (this.flagify.isEnabled('dark-mode')) {
  applyDarkTheme()
}

getValue<T>(flagKey: string, fallback: T): T

Returns the resolved value of a feature flag with a fallback.

const limit = this.flagify.getValue<number>('rate-limit', 100)

getVariant(flagKey: string, fallback: string): string

Returns the string variant of a multivariate flag.

const variant = this.flagify.getVariant('checkout-flow', 'control')

evaluate(flagKey: string, user: FlagifyUser): Promise<EvaluateResult>

Server-side evaluation with user targeting. Calls the Flagify API with user context.

const result = await this.flagify.evaluate('premium-feature', {
  id: 'user_123',
  email: '[email protected]',
  role: 'admin',
})
// result: { key: 'premium-feature', value: true, reason: 'targeting_rule' }

getClient(): Flagify

Returns the underlying @flagify/node client instance for advanced use cases.

Guard and decorators

@RequireFlag(key) + FeatureFlagGuard

Gate routes behind a feature flag. The guard reads metadata set by @RequireFlag and checks the flag state.

@Controller('beta')
@UseGuards(FeatureFlagGuard)
export class BetaController {
  // Only accessible when 'beta-access' is enabled
  @Get()
  @RequireFlag('beta-access')
  getBeta() {
    return { status: 'welcome to beta' }
  }

  // Only accessible when 'checkout-flow' equals 'variant-b'
  @Get('checkout')
  @RequireFlag({ key: 'checkout-flow', value: 'variant-b' })
  getNewCheckout() {
    return { flow: 'variant-b' }
  }
}

When identify is configured in the module options and value is specified, the guard performs a server-side evaluation with the user's context.

@FeatureFlag(key)

Parameter decorator that injects a flag value into a route handler.

@Controller('dashboard')
export class DashboardController {
  // Boolean flag — resolves via isEnabled()
  @Get()
  getDashboard(@FeatureFlag('new-dashboard') isNew: boolean) {
    return isNew ? { layout: 'v2' } : { layout: 'v1' }
  }

  // Typed value with fallback — resolves via getValue()
  @Get('products')
  getProducts(@FeatureFlag({ key: 'max-results', fallback: 20 }) max: number) {
    return { maxResults: max }
  }
}

Testing

FlagifyTestingModule

A drop-in replacement for FlagifyModule that uses in-memory mock flags. No HTTP calls, no API keys needed.

import { Test } from '@nestjs/testing'
import { FlagifyTestingModule, FlagifyService } from '@flagify/nestjs'

const module = await Test.createTestingModule({
  imports: [
    FlagifyTestingModule.withFlags({
      'new-checkout': true,
      'rate-limit': 50,
      'checkout-flow': 'variant-a',
    }),
  ],
  providers: [PaymentService],
}).compile()

const flagify = module.get(FlagifyService)

flagify.isEnabled('new-checkout')       // true
flagify.getValue('rate-limit', 100)     // 50
flagify.getVariant('checkout-flow', '') // 'variant-a'

Import the testing module from the @flagify/nestjs/testing entrypoint or directly from @flagify/nestjs.

API reference

| Export | Type | Description | |--------|------|-------------| | FlagifyModule | Module | Dynamic module -- forRoot() / forRootAsync() | | FlagifyService | Service | Injectable service for flag evaluation | | FeatureFlagGuard | Guard | Route guard that checks @RequireFlag metadata | | RequireFlag | Decorator | Method decorator to gate routes behind a flag | | FeatureFlag | Decorator | Parameter decorator to inject flag values | | FlagifyTestingModule | Module | Testing module with mock flags | | FlagifyModuleOptions | Type | Options for forRoot() | | FlagifyModuleAsyncOptions | Type | Options for forRootAsync() | | RequireFlagOptions | Type | Options for @RequireFlag() | | FeatureFlagParamOptions | Type | Options for @FeatureFlag() | | MockFlagMap | Type | Flag map for FlagifyTestingModule.withFlags() | | FLAGIFY_OPTIONS | Symbol | Injection token for module options | | REQUIRE_FLAG_KEY | String | Metadata key used by @RequireFlag |

Contributing

We welcome contributions. Please open an issue first to discuss what you'd like to change.

# Clone
git clone https://github.com/flagifyhq/javascript.git
cd javascript

# Install
pnpm install

# Development (watch mode)
pnpm run dev

# Build
pnpm run build

License

MIT -- see LICENSE for details.