| name | openfeature-eng |
| description | Implement OpenFeature feature flags in software projects. Use when adding feature flags with OpenFeature SDKs, configuring providers, setting up evaluation context, or integrating the OpenFeature MCP Server. |
OpenFeature Implementation
Guide for implementing OpenFeature - the open standard for feature flag management - across server and client applications.
When to Use This Skill
- Adding feature flags to a new or existing project
- Implementing OpenFeature Server SDKs (Go, Java, .NET, Node.js, PHP, Python, Ruby, Rust, Dart)
- Implementing OpenFeature Client SDKs (JavaScript, React, Angular, Kotlin, iOS/Swift)
- Configuring feature flag providers (flagd, LaunchDarkly, Split, etc.)
- Setting up evaluation context for targeting
- Using the OpenFeature MCP Server
This skill does NOT cover:
- Creating custom OpenFeature providers (see provider development docs)
- Vendor-specific flag management UIs
- Feature flag strategy/design patterns
Core Concepts
OpenFeature Architecture
┌─────────────────────────────────────────────────────────────┐
│ Application Code │
│ client.getBooleanValue("feature-x", false, context) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ OpenFeature SDK │
│ - Evaluation API │
│ - Hooks (before/after/error/finally) │
│ - Event handling │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Provider │
│ flagd | LaunchDarkly | Split | CloudBees | In-Memory │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Flag Management │
│ Flag definitions, rules, segments, rollouts │
└─────────────────────────────────────────────────────────────┘
Key Terms
| Term | Description |
|---|---|
| Provider | Backend that evaluates flags (flagd, LaunchDarkly, etc.) |
| Client | SDK instance for evaluating flags |
| Context | User/request attributes for targeting |
| Hook | Lifecycle callbacks for logging, metrics |
| Flag | Feature toggle with key, type, and default value |
Server SDK Implementations
Go
go get github.com/open-feature/go-sdk
package main
import (
"context"
"github.com/open-feature/go-sdk/openfeature"
"github.com/open-feature/go-sdk-contrib/providers/flagd/pkg"
)
func main() {
// Set up provider
provider := flagd.NewProvider()
openfeature.SetProvider(provider)
// Get client
client := openfeature.NewClient("my-app")
// Evaluation context
ctx := openfeature.NewEvaluationContext(
"user-123",
map[string]interface{}{
"email": "user@example.com",
"tier": "premium",
},
)
// Evaluate flags
enabled, _ := client.BooleanValue(
context.Background(),
"new-feature",
false,
ctx,
)
if enabled {
// New feature code
}
}
Java
<dependency>
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<version>1.7.0</version>
</dependency>
import dev.openfeature.sdk.*;
import dev.openfeature.contrib.providers.flagd.FlagdProvider;
public class FeatureFlags {
public static void main(String[] args) {
// Set provider
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProvider(new FlagdProvider());
// Get client
Client client = api.getClient("my-app");
// Evaluation context
EvaluationContext ctx = new ImmutableContext("user-123",
Map.of(
"email", new Value("user@example.com"),
"tier", new Value("premium")
)
);
// Evaluate flags
boolean enabled = client.getBooleanValue("new-feature", false, ctx);
if (enabled) {
// New feature code
}
}
}
.NET
dotnet add package OpenFeature
dotnet add package OpenFeature.Contrib.Providers.Flagd
using OpenFeature;
using OpenFeature.Contrib.Providers.Flagd;
// Set provider
var provider = new FlagdProvider();
await Api.Instance.SetProviderAsync(provider);
// Get client
var client = Api.Instance.GetClient("my-app");
// Evaluation context
var context = EvaluationContext.Builder()
.SetTargetingKey("user-123")
.Set("email", "user@example.com")
.Set("tier", "premium")
.Build();
// Evaluate flags
var enabled = await client.GetBooleanValueAsync("new-feature", false, context);
if (enabled)
{
// New feature code
}
Node.js / TypeScript
npm install @openfeature/server-sdk @openfeature/flagd-provider
import { OpenFeature } from '@openfeature/server-sdk';
import { FlagdProvider } from '@openfeature/flagd-provider';
// Set provider
await OpenFeature.setProviderAndWait(new FlagdProvider());
// Get client
const client = OpenFeature.getClient('my-app');
// Evaluation context
const context = {
targetingKey: 'user-123',
email: 'user@example.com',
tier: 'premium',
};
// Evaluate flags
const enabled = await client.getBooleanValue('new-feature', false, context);
if (enabled) {
// New feature code
}
NestJS Integration
npm install @openfeature/server-sdk @openfeature/nestjs-sdk @openfeature/flagd-provider
// app.module.ts
import { Module } from '@nestjs/common';
import { OpenFeatureModule } from '@openfeature/nestjs-sdk';
import { FlagdProvider } from '@openfeature/flagd-provider';
@Module({
imports: [
OpenFeatureModule.forRoot({
defaultProvider: new FlagdProvider(),
}),
],
})
export class AppModule {}
// feature.service.ts
import { Injectable } from '@nestjs/common';
import {
OpenFeatureClient,
BooleanFeatureFlag
} from '@openfeature/nestjs-sdk';
import { Client } from '@openfeature/server-sdk';
@Injectable()
export class FeatureService {
constructor(
@OpenFeatureClient() private client: Client,
) {}
@BooleanFeatureFlag({
flagKey: 'new-feature',
defaultValue: false,
})
async isNewFeatureEnabled(): Promise<boolean> {
return this.client.getBooleanValue('new-feature', false);
}
}
Python
pip install openfeature-sdk openfeature-provider-flagd
from openfeature import api
from openfeature.evaluation_context import EvaluationContext
from openfeature.contrib.provider.flagd import FlagdProvider
# Set provider
api.set_provider(FlagdProvider())
# Get client
client = api.get_client("my-app")
# Evaluation context
context = EvaluationContext(
targeting_key="user-123",
attributes={
"email": "user@example.com",
"tier": "premium",
}
)
# Evaluate flags
enabled = client.get_boolean_value("new-feature", False, context)
if enabled:
# New feature code
pass
Ruby
gem install openfeature-sdk openfeature-flagd-provider
require 'openfeature/sdk'
require 'openfeature/flagd/provider'
# Set provider
OpenFeature::SDK.configure do |config|
config.set_provider(OpenFeature::Flagd::Provider.new)
end
# Get client
client = OpenFeature::SDK.build_client(name: 'my-app')
# Evaluation context
context = OpenFeature::SDK::EvaluationContext.new(
targeting_key: 'user-123',
email: 'user@example.com',
tier: 'premium'
)
# Evaluate flags
enabled = client.fetch_boolean_value(
flag_key: 'new-feature',
default_value: false,
evaluation_context: context
)
if enabled
# New feature code
end
Rust
[dependencies]
open-feature = "0.2"
use open_feature::{
provider::NoOpProvider,
EvaluationContext, OpenFeature,
};
#[tokio::main]
async fn main() {
// Set provider
let mut api = OpenFeature::singleton_mut().await;
api.set_provider(NoOpProvider::default()).await;
// Get client
let client = api.create_client();
// Evaluation context
let context = EvaluationContext::default()
.with_targeting_key("user-123")
.with_custom_field("email", "user@example.com")
.with_custom_field("tier", "premium");
// Evaluate flags
let enabled = client
.get_bool_value("new-feature", Some(&context), None)
.await
.unwrap_or(false);
if enabled {
// New feature code
}
}
Dart
dependencies:
openfeature_dart_sdk: ^0.1.0
import 'package:openfeature_dart_sdk/openfeature_dart_sdk.dart';
void main() async {
// Set provider
final api = OpenFeatureAPI.instance;
await api.setProvider(InMemoryProvider());
// Get client
final client = api.getClient('my-app');
// Evaluation context
final context = EvaluationContext(
targetingKey: 'user-123',
attributes: {
'email': 'user@example.com',
'tier': 'premium',
},
);
// Evaluate flags
final enabled = await client.getBooleanValue(
'new-feature',
defaultValue: false,
context: context,
);
if (enabled) {
// New feature code
}
}
PHP
composer require open-feature/sdk open-feature/flagd-provider
<?php
use OpenFeature\OpenFeatureAPI;
use OpenFeature\Providers\Flagd\FlagdProvider;
use OpenFeature\implementation\flags\EvaluationContext;
// Set provider
$api = OpenFeatureAPI::getInstance();
$api->setProvider(new FlagdProvider());
// Get client
$client = $api->getClient('my-app');
// Evaluation context
$context = new EvaluationContext(
'user-123',
[
'email' => 'user@example.com',
'tier' => 'premium',
]
);
// Evaluate flags
$enabled = $client->getBooleanValue('new-feature', false, $context);
if ($enabled) {
// New feature code
}
Client SDK Implementations
React
npm install @openfeature/react-sdk @openfeature/web-sdk @openfeature/flagd-web-provider
// App.tsx
import { OpenFeatureProvider, useBooleanFlagValue } from '@openfeature/react-sdk';
import { FlagdWebProvider } from '@openfeature/flagd-web-provider';
const provider = new FlagdWebProvider({
host: 'localhost',
port: 8013,
});
function App() {
return (
<OpenFeatureProvider provider={provider}>
<FeatureComponent />
</OpenFeatureProvider>
);
}
function FeatureComponent() {
const enabled = useBooleanFlagValue('new-feature', false);
return enabled ? <NewFeature /> : <OldFeature />;
}
// With evaluation context
import { useOpenFeatureClient } from '@openfeature/react-sdk';
function UserFeature({ userId }: { userId: string }) {
const client = useOpenFeatureClient();
const enabled = useBooleanFlagValue('premium-feature', false, {
targetingKey: userId,
tier: 'premium',
});
return enabled ? <PremiumFeature /> : <StandardFeature />;
}
Angular
npm install @openfeature/angular-sdk @openfeature/web-sdk
// app.module.ts
import { NgModule } from '@angular/core';
import { OpenFeatureModule } from '@openfeature/angular-sdk';
import { InMemoryProvider } from '@openfeature/web-sdk';
@NgModule({
imports: [
OpenFeatureModule.forRoot({
provider: new InMemoryProvider({
'new-feature': {
disabled: false,
variants: { on: true, off: false },
defaultVariant: 'on'
},
}),
}),
],
})
export class AppModule {}
// feature.component.ts
import { Component } from '@angular/core';
import { BooleanFeatureFlag } from '@openfeature/angular-sdk';
@Component({
selector: 'app-feature',
template: `
<div *ngIf="isEnabled$ | async">
New Feature Content
</div>
`,
})
export class FeatureComponent {
@BooleanFeatureFlag({ flagKey: 'new-feature', defaultValue: false })
isEnabled$!: Observable<boolean>;
}
Kotlin (Android)
// build.gradle.kts
dependencies {
implementation("dev.openfeature:android-sdk:0.3.0")
}
import dev.openfeature.sdk.OpenFeatureAPI
import dev.openfeature.sdk.EvaluationContext
import dev.openfeature.contrib.providers.flagd.FlagdProvider
class FeatureFlags(context: Context) {
private val client: Client
init {
// Set provider
val api = OpenFeatureAPI.getInstance()
api.setProvider(FlagdProvider())
client = api.getClient("my-app")
}
suspend fun isNewFeatureEnabled(userId: String): Boolean {
val context = EvaluationContext(
targetingKey = userId,
attributes = mapOf(
"platform" to "android",
"version" to BuildConfig.VERSION_NAME
)
)
return client.getBooleanValue("new-feature", false, context)
}
}
iOS / Swift
// Package.swift
dependencies: [
.package(url: "https://github.com/open-feature/swift-sdk.git", from: "0.1.0")
]
import OpenFeature
class FeatureFlags {
private let client: Client
init() {
// Set provider
let api = OpenFeatureAPI.shared
api.setProvider(provider: InMemoryProvider())
client = api.getClient(name: "my-app")
}
func isNewFeatureEnabled(userId: String) async -> Bool {
let context = MutableContext(
targetingKey: userId,
structure: MutableStructure(
attributes: [
"platform": .string("ios"),
"version": .string(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "")
]
)
)
return await client.getBooleanValue(
key: "new-feature",
defaultValue: false,
context: context
)
}
}
Provider Configuration
flagd (Open Source)
# flagd-config.yaml
flags:
new-feature:
state: ENABLED
variants:
"on": true
"off": false
defaultVariant: "off"
targeting:
if:
- in:
- var: tier
- ["premium", "enterprise"]
- "on"
- "off"
# Run flagd
docker run -p 8013:8013 -v ./flagd-config.yaml:/config.yaml \
ghcr.io/open-feature/flagd:latest start --uri file:/config.yaml
In-Memory Provider (Testing)
import { InMemoryProvider } from '@openfeature/server-sdk';
const flags = {
'new-feature': {
disabled: false,
variants: { on: true, off: false },
defaultVariant: 'on',
},
'feature-limit': {
disabled: false,
variants: { low: 10, medium: 50, high: 100 },
defaultVariant: 'medium',
},
};
await OpenFeature.setProviderAndWait(new InMemoryProvider(flags));
OpenFeature MCP Server
The OpenFeature MCP Server enables flag evaluation through Claude.
Installation
npx @openfeature/mcp-server
Configuration
{
"mcpServers": {
"openfeature": {
"command": "npx",
"args": ["@openfeature/mcp-server"],
"env": {
"FLAGD_HOST": "localhost",
"FLAGD_PORT": "8013"
}
}
}
}
Usage
The MCP server provides tools for:
- Evaluating feature flags
- Listing available flags
- Getting flag metadata
Hooks
Logging Hook
import { Hook, HookContext, EvaluationDetails } from '@openfeature/server-sdk';
const loggingHook: Hook = {
before: (hookContext: HookContext) => {
console.log(`Evaluating flag: ${hookContext.flagKey}`);
},
after: (hookContext: HookContext, details: EvaluationDetails<any>) => {
console.log(`Flag ${hookContext.flagKey} = ${details.value}`);
},
error: (hookContext: HookContext, error: Error) => {
console.error(`Error evaluating ${hookContext.flagKey}:`, error);
},
};
client.addHooks(loggingHook);
Metrics Hook
const metricsHook: Hook = {
after: (hookContext, details) => {
metrics.increment('feature_flag.evaluation', {
flag: hookContext.flagKey,
variant: details.variant,
reason: details.reason,
});
},
};
Testing
Unit Testing with Mocks
import { OpenFeature, InMemoryProvider } from '@openfeature/server-sdk';
describe('Feature Tests', () => {
beforeEach(async () => {
await OpenFeature.setProviderAndWait(
new InMemoryProvider({
'new-feature': {
disabled: false,
variants: { on: true, off: false },
defaultVariant: 'on',
},
})
);
});
it('should show new feature when enabled', async () => {
const client = OpenFeature.getClient();
const enabled = await client.getBooleanValue('new-feature', false);
expect(enabled).toBe(true);
});
});
Best Practices
- Set default values defensively - Always provide sensible defaults
- Use targeting keys - Enable user-level targeting and consistency
- Add evaluation context - Include relevant attributes for targeting
- Implement hooks - Add logging and metrics for observability
- Clean up flags - Remove flags after features are fully rolled out
- Use typed values - Prefer specific value types over strings
- Test both paths - Test feature on and off states