Skip to content

Feature Flags

Jeremy Asuncion edited this page Jul 15, 2024 · 2 revisions

Feature flagging is a technique for enabling or disabling features within our code. Because we have daily releases to production, we need a way to be able to work on large features iteratively without delaying a release or using large PRs / feature branches. The solution is to hide our features behind a conditional based on the value of a feature flag. By doing this, we can iteratively work on a large feature via multiple PRs without impacting the existing flow of our UI until it's time to ship the feature to production.

All feature flag utilities are stored within the featureFlag.ts module. There are 5 key aspects of the feature flag module:

  1. Feature flag environment
  2. Feature flag key
  3. Feature flag map
  4. getFeatureFlag() util function
  5. useFeatureFlag() React hook

Feature Flag Environent

There are 4 environment values that correspond to our deployment environments. They're defined as a string literal type:

export type FeatureFlagEnvironment = 'local' | 'dev' | 'staging' | 'prod'

The environment strings are used for determining which environment a particular feature flag is enabled for.

Feature Flag Key

The feature flag key is a string literal type that defines all possible keys for our feature flag. This is primarily used to strictly type the keys that can be used when using the feature flag util functions.

export type FeatureFlagKey =
  | 'someFeature1'
  | 'someFeature2'
  | 'someFeature3'
  | 'someFeature4'

Feature Flag Map

The feature flag map is a mapping of feature flags to a list of environments the feature flag is enabled for:

export const FEATURE_FLAGS: Record<FeatureFlagKey, FeatureFlagEnvironment[]> = {
  someFeature1: ['local', 'dev'],
  someFeature2: ['local', 'dev'],
  someFeature3: ['local', 'dev', 'staging'],
  someFeature4: ['local', 'dev', 'staging', 'prod'],
}

getFeatureFlag() util

The getFeatureFlag() util function is used for getting the value of the feature flag. It's a generic function that takes in the environment and URL search params as input, and returns the true or false depending on if the flag is enabled for the environment input or if a URL search param override is provided. This function is primarily useful in non-React contexts (i.e. on the server side).

useFeatureFlag() hook

The useFeatureFlag() function is a React hook that serves as a convenient interface for using the getFeatureFlag() function without needing to pass in the environment or URL search params. This function should be used over the getFeatureFlag() function in most use cases when working in React.

Adding new feature flags

When adding a new feature flag, all you need to do is:

  1. Add the feature flag key
  2. Add the local and dev environments to the feature flag map
  3. Conditionally render your feature code based on the feature flag value
// Add new feature flag key
export type FeatureFlagKey =
  | 'someFeature1'
  | 'someFeature2'
  | 'someFeature3'
  | 'someFeature4'
+ | 'newFeature


// Add to feature flag map
export const FEATURE_FLAGS: Record<FeatureFlagKey, FeatureFlagEnvironment[]> = {
  someFeature1: ['local', 'dev'],
  someFeature2: ['local', 'dev'],
  someFeature3: ['local', 'dev', 'staging'],
  someFeature4: ['local', 'dev', 'staging', 'prod'],
+ newFeature: ['local', 'dev'],
}
import { useFeatureFlag } from 'app/utils/featureFlag'

function Example() {
  const isNewFeatureEnabled = useFeatureFlag('newFeature')

  if (isNewFeatureEnabled) {
    return <NewCode />
  }

  return <OldCode />
}

Release to other environments

When a feature is ready, you can release it to another environment by adding the environment key to the feature flag map and wait for the next deployment.

export const FEATURE_FLAGS: Record<FeatureFlagKey, FeatureFlagEnvironment[]> = {
  someFeature1: ['local', 'dev'],
  someFeature2: ['local', 'dev'],
  someFeature3: ['local', 'dev', 'staging'],
  someFeature4: ['local', 'dev', 'staging', 'prod'],
- newFeature: ['local', 'dev'],
+ newFeature: ['local', 'dev', 'staging', 'prod'],
}

Overriding Feature Flags

Feature flags can be overridden by specifying a special query parameter to enable or disable a particular feature. The --enable-feature parameter will enable a feature, and conversely the --disable-feature parameter will disable a feature.

For example, if the new feature is on the browse datasets page, you could enable the feature by visiting:

https://cryoetdataportal.czscience.com/browse-data/datasets?enable-feature=newFeature