feature-flags · react — Claude Code skill: React flags and @gate
A skill for working with feature flags in the React repo: where flags live, how to gate tests, and why a channel-specific test fails.
npx skills add react/react --skill feature-flags -a claude-codeWhat feature-flags does
The skill lays out how feature flags work in React. Defaults sit in packages/shared/ReactFeatureFlags.js, with per-channel forks in ReactFeatureFlags.www.js, ReactFeatureFlags.native-fb.js and ReactFeatureFlags.test-renderer.js. A flag that needs to vary in www or React Native gets __VARIANT__ in the fork file.
There are two ways to gate tests. The @gate pragma works at the test level, for features that simply do not exist without the flag: the test is skipped rather than failed. Inline gate(flags => flags.name) is for cases where both paths should run and the expectations differ. The syntax matters, gate('name') will not work.
Adding a flag takes four steps: a default in the main file, the same entry in every fork file, __VARIANT__ where variation is wanted, and a gate in the tests. Skipping one fork file is the usual mistake, and it throws off how that channel's tests behave. /flags shows flag states across channels, and /flags --diff <channel1> <channel2> compares two of them.
What it helps with
- find which file holds a given feature flag
- gate a test with
@gateso it skips without the flag - add a new flag to every fork file at once
- compare flag states between two channels
- run www tests in both
__VARIANT__states
Example prompts for the agent
- The view transitions test is failing — check whether it needs
@gate enableViewTransition. - Add the new flag to
ReactFeatureFlags.jsand every fork file, set__VARIANT__in www. - Compare flags across channels:
/flags --diff www native-fb.
How to install feature-flags
1Skills CLI (Vercel)
npx skills add react/react --skill feature-flags -a claude-code2Manually: put the files in place
~/.claude/skills/feature-flags/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/feature-flags/
1Skills CLI (Vercel)
npx skills add react/react --skill feature-flags -a codex2Manually: put the files in place
.agents/skills/feature-flags/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add react/react --skill feature-flags -a cursor2Manually: put the files in place
.cursor/skills/feature-flags/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install react/react feature-flags2Manually: put the files in place
.github/skills/feature-flags/SKILL.md1Skills CLI (Vercel)
npx skills add react/react --skill feature-flags -a gemini-cli2Platform CLI
gemini skills install https://github.com/react/react --path .claude/skills/feature-flagsManually: put the files in place
.devin/skills/feature-flags/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add react/react --skill feature-flags -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about feature-flags
How do I install feature-flags in Claude Code?
Run npx skills add react/react --skill feature-flags -a claude-code. The skill lands at ~/.claude/skills/feature-flags/SKILL.md.
What does the feature-flags skill do?
It covers React feature flags: which file holds what, gating tests with @gate and inline gate(), adding a new flag, and tracking down a failing test in one channel.
How is @gate different from inline gate()?
@gate applies to the whole test and skips it when the flag is off. Inline gate(flags => flags.name) keeps the test running and switches expectations inside it.
Source text
SKILL.md · MIT
---
name: feature-flags
description: Use when feature flag tests fail, flags need updating, understanding @gate pragmas, debugging channel-specific test failures, or adding new flags to React.
---
# React Feature Flags
## Flag Files
| File | Purpose |
|------|---------|
| `packages/shared/ReactFeatureFlags.js` | Default flags (canary), `__EXPERIMENTAL__` overrides |
| `packages/shared/forks/ReactFeatureFlags.www.js` | www channel, `__VARIANT__` overrides |
| `packages/shared/forks/ReactFeatureFlags.native-fb.js` | React Native, `__VARIANT__` overrides |
| `packages/shared/forks/ReactFeatureFlags.test-renderer.js` | Test renderer |
## Gating Tests
### `@gate` pragma (test-level)
Use when the feature is completely unavailable without the flag:
```javascript
// @gate enableViewTransition
it('supports view transitions', () => {
// This test only runs when enableViewTransition is true
// and is SKIPPED (not failed) when false
});
```
### `gate()` inline (assertion-level)
Use when the feature exists but behavior differs based on flag:
```javascript
it('renders component', async () => {
await act(() => root.render(<App />));
if (gate(flags => flags.enableNewBehavior)) {
expect(container.textContent).toBe('new output');
} else {
expect(container.textContent).toBe('legacy output');
}
});
```
## Adding a New Flag
1. Add to `ReactFeatureFlags.js` with default value
2. Add to each fork file (`*.www.js`, `*.native-fb.js`, etc.)
3. If it should vary in www/RN, set to `__VARIANT__` in the fork file
4. Gate tests with `@gate flagName` or inline `gate()`
## Checking Flag States
Use `/flags` to view states across channels. See the `flags` skill for full command options.
## `__VARIANT__` Flags (GKs)
Flags set to `__VARIANT__` simulate gatekeepers - tested twice (true and false):
```bash
/test www <pattern> # __VARIANT__ = true
/test www variant false <pattern> # __VARIANT__ = false
```
## Debugging Channel-Specific Failures
1. Run `/flags --diff <channel1> <channel2>` to compare values
2. Check `@gate` conditions - test may be gated to specific channels
3. Run `/test <channel> <pattern>` to isolate the failure
4. Verify flag exists in all fork files if newly added
## Common Mistakes
- **Forgetting both variants** - Always test `www` AND `www variant false` for `__VARIANT__` flags
- **Using @gate for behavior differences** - Use inline `gate()` if both paths should run
- **Missing fork files** - New flags must be added to ALL fork files, not just the main one
- **Wrong gate syntax** - It's `gate(flags => flags.name)`, not `gate('name')`
© react · MIT · react/react