Stable Product Feature Releases through OpenFeature

Introduction

I used to think keeping things simple was best — change the code or flip an environment variable — why introduce more complex package management or third-party services? But in real incidents you don’t have the time to slowly deploy and debug, so it’s necessary to use a more complete Feature Flag strategy to reduce the risk of releasing features and to lower the chance of heart-stopping moments.

So in this article we’ll take a closer look at how to use OpenFeature🔗, an open-source standard, ecosystem, and SDK tooling for Feature Flag practices, to build a smoother and more stable product feature rollout experience.

Current problems

  • Development is done but the business side isn’t ready
  • Features are distributed across multiple services
  • Experimental features

Typically implementing a Feature Flag only requires embedding a variable in the code or using an environment variable. While simple and workable, this approach is hard to manage and track, and cannot flexibly and quickly switch to respond to complex incidents.

const isJira1234FeatureFlagOn = import.meta.env.VITE_Jira_1234
if (isJira1234FeatureFlagOn) {
// Flag on
} else {
// Flag off
}

What is OpenFeature?

OpenFeature🔗 is an open-source, multi-vendor-supported open standard for implementing common Feature Flag practices:

Cloud

Your App

feature-flagging client

OpenFeature SDK

eval. context

eval. context

flag eval.

flag evaluation API

flag eval.

OpenFeature Provider

Feature Flag Service

OpenFeature glossary

  • Evaluation API🔗
    • Allows developers to evaluate Feature Flags and use the evaluation result to influence control flow or behavior.
  • Evaluation Context🔗
    • A container for arbitrary contextual data (e.g., user_id, region, email) that can be used as the basis for dynamic evaluations.
  • Providers🔗
    • Responsible for mapping the parameters given to the Evaluation API to their equivalent representation in the associated flag management system. Providers can wrap vendor SDKs, call custom flag evaluation REST APIs, or even parse locally stored files to resolve flag values.
  • Hooks🔗
    • Used to add arbitrary behavior at different points in the lifecycle.
  • Events🔗
    • Triggered when the system emits specific events (e.g., Provider ready, flag configuration change, Provider failure). This lets applications react in real time to environmental changes.

How to use OpenFeature?

Using OpenFeature is like “configuring a socket” and “plugging in a plug” — it mainly consists of three steps:

1. Configure a Provider (set up the socket)

main.js
import { OpenFeature, InMemoryProvider } from '@openfeature/web-sdk';
const provider = new InMemoryProvider(flagConfig);
await OpenFeature.setContext({ user_id: '123' });
await OpenFeature.setProviderAndWait(provider);
const flagConfig = {
'show-welcome-banner': {
disabled: false,
variants: {
on: true,
off: false
},
defaultVariant: 'on',
// Optional: contextEvaluator determines the flag result based on context
// This is a feature specific to InMemoryProvider; other providers typically handle this on the server side.
contextEvaluator: (ctx: any) => {
if (ctx.user_id === '123') return 'on';
return 'off';
}
},
'button-color': {
disabled: false,
variants: {
green: 'green',
red: 'red',
gray: 'gray'
},
defaultVariant: 'green',
contextEvaluator: (ctx: any) => 'green'
},
'retry-count': {
disabled: false,
variants: {
five: 5,
ten: 10
},
defaultVariant: 'five'
},
'config-object': {
disabled: false,
variants: {
production: {
env: 'production',
apis: ['v1', 'v2'],
},
dev: {
env: 'development',
apis: ['v1'],
}
},
defaultVariant: 'production'
},
};

2. Get a Client (obtain access interface)

Client is the entry point to interact with Feature Flags. You can get different Clients for different business domains (e.g., user-service or billing).

const client = OpenFeature.getClient('my-app-name');

3. Perform evaluation (get results)

Use the APIs provided by the Client to obtain flag values. You need to provide the flag name, a default value, and an optional evaluation context.

// Dynamically provide context (such as user ID)
const context = { targetingKey: 'user-123', region: 'asia' };
const isNewFeatureEnabled = await client.getBooleanValue(
'new-cool-feature',
false,
context
);
if (isNewFeatureEnabled) {
// 執行新功能代碼
}

Choosing the right solution

Above we used the default official practice InMemoryProvider via the web/sdk in the frontend to get familiar with OpenFeature’s basic workflow. In practice you can choose from many available Providers🔗.

You can also hook up a backend flagConfig to dynamically change Feature Flags:

Backend
// Node.js/Express
app.get('/api/feature-flags', authenticate, (req, res) => {
const userId = req.user.id;
const userRegion = req.user.region;
const flags = {
'show-welcome-banner': {
disabled: false,
variants: { on: true, off: false },
defaultVariant: userId === '123' ? 'on' : 'off'
}
};
res.json(flags);
});
Frontend
const response = await fetch('/api/feature-flags', {
headers: {
'Authorization': `Bearer ${token}`
}
});
const flagConfig = await response.json();
const provider = new InMemoryProvider(flagConfig);
await OpenFeature.setProviderAndWait(provider);

Although the above approach works, InMemoryProvider is typically used for testing or static configuration. It’s better to adopt other Feature Flag infrastructures such as flagd🔗 and management interfaces like unleash🔗.

// 2. The frontend uses a flagged provider
import { FlagdWebProvider } from '@openfeature/flagd-web-provider';
const provider = new FlagdWebProvider({
host: 'https://your-flagd-server.com',
port: 8013
});
await OpenFeature.setProviderAndWait(provider);

Further reading