Skip to content

FeatureFlagBehavior

Defined in: packages/pipeline-feature-flags/src/feature-flag.behavior.ts:172

Pipeline behavior that gates a handler behind an OpenFeature boolean flag.

Provider-agnostic by design: it talks only to the OpenFeature Client, so the backing provider (Unleash, Flagsmith, LaunchDarkly, a local file, …) is a drop-in swap of the client passed to the constructor (see createFeatureFlagClient). OpenFeature remains the feature-flag abstraction; this behavior adds only the pipeline-specific semantics that an application repeatedly needs.

Resolution of the effective options for a handler:

  1. Application-wide defaults, the second constructor argument.
  2. Per-operation options from the featureFlag({ ... }) entry, shallow-merged on top of the defaults (handler keys win).

Behavior:

  • No flag configured → transparent pass-through.
  • Flag evaluates true and optional allowedVariants accepts the provider variant → run the handler.
  • Final gate disabled → return fallback(context) when provided, otherwise throw FeatureDisabledError.
  • Provider evaluation error → use the configured defaultValue by default, or throw FeatureFlagEvaluationError with errorPolicy: 'throw'.

Percentage/gradual rollouts should use a stable user/account/device/tenant identity through targetingKeyFactory.

Simple gate

class NewCheckoutHandler {
@pipeline.wrap({ kind: 'command' }, [FeatureFlagBehavior, { flag: 'new-checkout' }])
async handle(command: NewCheckoutCommand) {}
}

Sticky user rollout with graceful fallback

class GetRecommendationsHandler {
@pipeline.wrap({ kind: 'query' }, [FeatureFlagBehavior, {
flag: 'recommendations-v2',
targetingKeyFactory: (ctx) =>
ctx.items.get('currentUserId') as string | undefined,
fallback: () => [],
}])
async handle(query: GetRecommendationsQuery) {}
}

Run only for one experiment variant

@pipeline.wrap({ kind: 'command' }, [FeatureFlagBehavior, {
flag: 'checkout-experiment',
allowedVariants: ['treatment-a'],
}])

Make flag-provider failure visible instead of using the default

@pipeline.wrap({ kind: 'command' }, [FeatureFlagBehavior, {
flag: 'critical-kill-switch',
errorPolicy: 'throw',
}])

new FeatureFlagBehavior(client, defaults?, moduleContext?, logger?, moduleTargetingKeyFactory?): FeatureFlagBehavior

Defined in: packages/pipeline-feature-flags/src/feature-flag.behavior.ts:223

Client

FeatureFlagBehaviorOptions

EvaluationContext

PipelineLogger

TargetingKeyFactory

FeatureFlagBehavior

readonly static [PIPELINE_BEHAVIOR_CONTRACT]: IPipelineBehaviorContract

Defined in: packages/pipeline-feature-flags/src/feature-flag.behavior.ts:177

handle(context, next): Promise<unknown>

Defined in: packages/pipeline-feature-flags/src/feature-flag.behavior.ts:239

IPipelineContext

NextDelegate

Promise<unknown>

IPipelineBehavior.handle


resolveEffectiveOptions(options?): FeatureFlagBehaviorOptions

Defined in: packages/pipeline-feature-flags/src/feature-flag.behavior.ts:370

Shallow-merges pipeline-level options over the application defaults.

FeatureFlagBehaviorOptions

FeatureFlagBehaviorOptions

IPipelineBehaviorOptionsResolver.resolveEffectiveOptions