4 min read

Migrating from In-House Feature Flagging with OpenFeature

Discover how the OpenFeature standard and new Multi-Provider utility can help you migrate away from your in-house flagging solution.
Migrating from In-House Feature Flagging with OpenFeature
Photo by Jeffrey Hamilton / Unsplash

Many teams use feature flags as a technique for continuously integrating and merging work-in-progress code while hiding unreleased features from end-users. While there are many vendors that provide feature flagging solutions, some teams prefer to build their system in-house initially. This allows them to determine if feature flagging is right for them. As their needs grow and they outgrow the capabilities of their in-house system, they can migrate to a full-featured SaaS product.

Especially early on, building your own flagging system is a viable option, but in order to obtain and use the values of flags you will need some kind of library or code interface for interacting with your flags. That might look something like this:

import { getFlag } from 'myFlaggingService'

const defaultValue = false
const userData = {id: 'myUser'}
const myFlagValue = getFlag('flag-key', userData, defaultValue)

Over time, you’ll have tens or hundreds of these types of calls throughout your code base.

Now let’s say you’ve outgrown your in-house flagging system, and have the desire to change to a more powerful system (like DevCycle). To do so, you would need to replace all of those hundreds of lines of code with calls to the DevCycle SDK. You could also create your own utility which can retrieve flags from both your existing system and the DevCycle SDK. Unfortunately, doing so means you have to manage the complexity of initializing and waiting for flag data from the old and new system, handling errors, and falling back to default values.

Instead of building that utility yourself, it’s probably a good idea to use the industry standard interface already created for this purpose: OpenFeature.

What is OpenFeature?

OpenFeature is a CNCF incubating project which aims to provide an open-source, standardized interface for evaluating feature flags in code. It does so by separating the SDK interface that your code calls, from the source of data and logic that provides the values of flags. That data source is called a “Provider”.

When choosing how to integrate feature flags in your code, following the industry standard means you unlock a lot of advantages:

  • production-ready SDKs that take care of all the hard stuff with fetching configuration data, error handling, and verifying inputs
  • standard interface that works the same in your code regardless of which provider you use
  • reduced maintenance burden by eliminating a piece of code you have to maintain

OpenFeature already has a wide array of providers for various feature flagging systems, but it’s also easy to write your own provider.

Even when using your own in-house flagging system, it is recommended to access them via an OpenFeature SDK by building a Provider to fetch their data. Now you have an industry standard system around your flags, making future maintenance or migration simple. Using it is as simple as:

const myFlagProvider = new MyFlagProvider()
await OpenFeature.setProviderAndWait(myFlagProvider)

openFeatureClient = OpenFeature.getClient()
const value = await openFeatureClient.getStringValue(
	'flag-key', 
	'default value', 
	someUser
)

Migrating Flag Systems

Is your home-grown solution not cutting it anymore, or there’s an advanced feature you want from a SaaS feature flag management platform that you can’t build yourself? With OpenFeature in place, it’s now pretty straightforward to swap providers as you see fit. Assuming all your flagging data has been ported over from your old system to the new one, migrating is as easy as swapping providers in OpenFeature:

// before
const myFlagProvider = new MyFlagProvider()
await OpenFeature.setProviderAndWait(myFlagProvider)

// after
const devcycleProvider = new DevCycleProvider()
await OpenFeature.setProviderAndWait(devcycleProvider)

Now all your existing flag calls will just start using DevCycle instead:

openFeatureClient = OpenFeature.getClient()
// now this uses DevCycle!
const value = await openFeatureClient.getStringValue(
	'flag-key', 
	'default value', 
	someUser
)

This works if the new system has all your flag data ported over from the old system, but what if that’s not the case? Maybe you’re conducting a slow migration over time, or only creating new flags in the new system while keeping old ones where they are. Swapping providers as shown above won’t work in that case, because you need to use both systems at once.

Luckily, OpenFeature has a solution for that as well: the Multi-Provider.

Multi-Provider

The Multi-Provider is a utility provided by OpenFeature which allows you to use multiple providers at once, defining rules for which provider’s result should be used during each flag evaluation. Setting it up is simple:

const multiProvider = new MultiProvider(
	[
		{
			provider: new InHouseFlagsProvider(),
		},
		{
			provider: new DevCycleProvider()
		}
	]
)
await OpenFeature.setProviderAndWait(multiProvider)

openFeatureClient = OpenFeature.getClient()
const value = await openFeatureClient.getStringValue(
	'flag-key', 
	'default value', 
	someUser
)

With this technique, you can perform a slow migration between flagging systems, or even maintain a permanent “multiple providers” setup where different flags can come from different places.

By default, the Multi-Provider will evaluate each provider in order. If a provider indicates that it does not have a flag, the Multi-Provider will proceed to the next provider until a successful result is obtained. Otherwise, the SDK will serve the default value.

Picture a scenario where most of your flags are in your old system, but newly added flags are only in DevCycle. With the setup shown above, your old system will continue serving values for the flags it knows about, while passing the decision on to DevCycle for any new flag that it doesn’t have a value for. Over time, you can migrate all your flags over, or continue using both systems indefinitely.

If the default behaviour for evaluating providers does not suit your use case, the Multi-Provider also supports the concept of “evaluation strategies” which can be used to override it. There are several different strategies provided out-of-the-box, and it’s also easy to implement your own. Check out the docs on Multi-Provider strategies for more information.

Conclusion

OpenFeature provides a powerful, industry standard interface for evaluating feature flags in code. Even if you’re using your own in-house system, it’s definitely a good idea to wrap it in an OpenFeature SDK for better maintainability and future migration potential.

When you’re ready to move to a more feature-rich feature management platform like DevCycle, your code will already be set up for a seamless transition. Take advantage of the Multi-Provider utility to slowly move flags over to your new system without having to change any evaluation code, or maintain multiple flag sources indefinitely.