Use when: implementing, creating, testing, or debugging feature flags in Primer React. Covers useFeatureFlag hook, FeatureFlags provider, DefaultFeatureFlags, FeatureFlagScope, Storybook integration, and the feature flag lifecycle at GitHub.
72
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Feature flags provide a way to incrementally build and deliver changes in Primer alongside the feature flag system at GitHub. They help build confidence in changes and improve the reliability of releases.
Feature flags are implemented in packages/react/src/FeatureFlags/ with these core pieces:
| File | Purpose |
|---|---|
FeatureFlags.tsx | React context provider component |
useFeatureFlag.ts | Hook to check if a flag is enabled |
FeatureFlagScope.ts | Class that manages flag collections and merging |
DefaultFeatureFlags.ts | Default flag values (all flags listed here) |
FeatureFlagContext.ts | React context definition |
index.ts | Public exports |
Feature flags are exported from @primer/react/experimental:
import {FeatureFlags, useFeatureFlag, DefaultFeatureFlags} from '@primer/react/experimental'They are NOT exported from the main @primer/react entry point.
Register your flag in packages/react/src/FeatureFlags/DefaultFeatureFlags.ts with a default value of false:
export const DefaultFeatureFlags = FeatureFlagScope.create({
// ...existing flags...
primer_react_my_new_feature: false,
})useFeatureFlag in your componentimport {useFeatureFlag} from '../FeatureFlags'
function MyComponent() {
const enabled = useFeatureFlag('primer_react_my_new_feature')
if (enabled) {
return <NewBehavior />
}
return <CurrentBehavior />
}primer_react_ for flags in the @primer/react packageprimer_react_my_feature_namefunction ExampleComponent({children}) {
const enabled = useFeatureFlag('primer_react_my_feature')
return (
<button
onClick={() => {
if (enabled) {
// new behavior
} else {
// current behavior
}
}}
>
{children}
</button>
)
}function ExampleComponent(props) {
const enabled = useFeatureFlag('primer_react_my_feature')
if (enabled) {
return <ExampleComponentNext {...props} />
}
return <ExampleComponentClassic {...props} />
}function MyOverlay() {
const enabled = useFeatureFlag('primer_react_my_feature')
return <div data-my-feature={enabled ? '' : undefined} />
}packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx)const cssAnchorPositioning = useFeatureFlag('primer_react_css_anchor_positioning')
useEffect(() => {
if (cssAnchorPositioning && !hasLoadedAnchorPositioningPolyfill.current) {
applyAnchorPositioningPolyfill()
hasLoadedAnchorPositioningPolyfill.current = true
}
}, [open, overlayRef, updateOverlayRef, cssAnchorPositioning])packages/react/src/Breadcrumbs/Breadcrumbs.tsx)const overflowMenuEnabled = useFeatureFlag('primer_react_breadcrumbs_overflow_menu')Wrap your component with the FeatureFlags provider to set flag values in tests:
import {FeatureFlags} from '../../FeatureFlags'
// Test with flag enabled
render(
<FeatureFlags flags={{primer_react_my_feature: true}}>
<MyComponent />
</FeatureFlags>,
)
// Test with flag disabled (or omit the wrapper to use default values from DefaultFeatureFlags)
render(
<FeatureFlags flags={{primer_react_my_feature: false}}>
<MyComponent />
</FeatureFlags>,
)falseFeatureFlags providers merge flags — inner values override outer valuesimport {FeatureFlags} from '../../FeatureFlags'
export const WithFeatureEnabled = () => (
<FeatureFlags flags={{primer_react_my_feature: true}}>
<MyComponent />
</FeatureFlags>
)
export const WithFeatureDisabled = () => <MyComponent />Storybook's global preview (packages/react/.storybook/preview.jsx) already wraps all stories in a FeatureFlags provider, using DefaultFeatureFlags as the source of default values and toolbar options. In most cases you only need to register your flag in DefaultFeatureFlags.ts; you do not need to manually add it to the FeatureFlags wrapper.
To enable a flag globally via environment, add its exact flag name (for example, primer_react_my_feature) to the featureFlagEnvList set in preview.jsx, and set the corresponding env var to 1 (for example, VITE_primer_react_my_feature=1). The preview code reads import.meta.env[\VITE*${flag}`], so the part after VITE*` must match the flag string exactly.
DefaultFeatureFlags.ts with value falseuseFeatureFlag() in components, write tests for both statesDefaultFeatureFlags.tsSet your flag to true in DefaultFeatureFlags.ts to enable it by default for CI testing. Set it back to false before merging.
FeatureFlagScope.create(flags) — Creates a scope from a plain object {[key: string]: boolean}FeatureFlagScope.merge(a, b) — Merges two scopes; b values override aFeatureFlags component merges parent context flags with the provided flags propDefaultFeatureFlags is the initial context value — it defines all known flagsCheck packages/react/src/FeatureFlags/DefaultFeatureFlags.ts for the current list of all registered feature flags and their default values.
b111781
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.