Skip to content

React SDK Reference

TL;DR: Install @featureflip/react-sdk, wrap your tree in <FeatureflipProvider>, call useFeatureFlag('flag-key', false) in components — re-renders automatically.

The @featureflip/react package wraps the Browser SDK in idiomatic React: a <FeatureflipProvider> at the root of your tree, and a useFlag hook in any component that needs to read feature flag values. Components re-render automatically when a flag’s value changes — no manual subscriptions, no global event bus, no forceUpdate plumbing. The package supports both React 18 and React 19 and works with the React Compiler, Server Components, and Suspense.

Internally, the hooks use React 18’s useSyncExternalStore so that flag reads are concurrent-mode safe and tearing-free. Snapshot identity is stable across re-renders (memoized via a useRef cache keyed on a JSON serialization), so a flag returning the same value won’t trigger spurious re-renders even when other flags update around it. The provider is hardened against React StrictMode’s intentional double-mount/double-effect behavior: the underlying Browser SDK (v2.0+) is singleton-by-construction via FeatureflipClient.get(clientKey, ...), so StrictMode’s simulated unmount/remount cycle returns handles sharing the same underlying core — the refcount stays positive across the cycle and the SSE connection is never actually torn down. Multiple <FeatureflipProvider> instances with the same clientKey (for example, in a micro-frontend architecture) likewise share one connection.

The provider’s identify() method updates the active context (e.g., after sign-in) and the new flag values flow through useFlag automatically. Errors are surfaced via the provider’s 'error' event so you can show fallback UI without try/catching every component. This is the recommended SDK for any React app — Next.js, Remix, Vite, CRA, React Native Web — that needs in-app percentage rollouts and targeting rules reacting to user state in real time.

View source on GitHub

  • React 18.0+ or 19.0+
  • Node.js 20.19.0+ (for build tooling)
Terminal window
npm install @featureflip/react-sdk @featureflip/browser-sdk

Wrap your app with FeatureflipProvider, then use useFeatureFlag in any component.

import { FeatureflipProvider, useFeatureFlag } from '@featureflip/react-sdk';
function App() {
return (
<FeatureflipProvider clientKey="your-client-sdk-key">
<Banner />
</FeatureflipProvider>
);
}
function Banner() {
const showBanner = useFeatureFlag('show-banner', false);
if (!showBanner) return null;
return <div>New feature available!</div>;
}

Wraps your component tree and manages the FeatureflipClient lifecycle. Creates the client on mount, calls initialize(), and cleans up on unmount.

PropTypeDefaultDescription
clientKeystring(required)Client SDK key
contextRecord<string, unknown>undefinedEvaluation context (user attributes)
baseUrlstringundefinedEvaluation API base URL
streamingbooleanundefinedEnable SSE streaming

When the context prop changes, the provider automatically calls identify() and re-evaluates all flags.

Returns the evaluated value of a flag. The component re-renders automatically when the flag value changes via streaming or identify().

The type of defaultValue determines which variation method is called internally.

const enabled = useFeatureFlag('new-checkout', false); // boolean
const color = useFeatureFlag('button-color', 'blue'); // string
const limit = useFeatureFlag('rate-limit', 100); // number
const config = useFeatureFlag('ui-config', { sidebar: true }); // object

useFeatureflipStatus(): { isReady, isError, error }

Section titled “useFeatureflipStatus(): { isReady, isError, error }”

Returns the initialization status of the client. Useful for showing loading states.

function StatusGate({ children }: { children: React.ReactNode }) {
const { isReady, isError, error } = useFeatureflipStatus();
if (isError) return <div>Error: {error?.message}</div>;
if (!isReady) return <div>Loading...</div>;
return <>{children}</>;
}
// Use inside a FeatureflipProvider
<FeatureflipProvider clientKey="your-client-sdk-key">
<StatusGate>
<Main />
</StatusGate>
</FeatureflipProvider>

Returns the underlying FeatureflipClient instance for direct access — for example, calling identify() after login.

You can identify users in two ways:

Via context prop — the provider calls identify() automatically when the prop changes:

import { useState } from 'react';
function App() {
const [user, setUser] = useState(null);
return (
<FeatureflipProvider
clientKey="your-client-sdk-key"
context={user ? { user_id: user.id, plan: user.plan } : undefined}
>
<Main />
</FeatureflipProvider>
);
}

Via the client directly:

function LoginPage() {
const client = useFeatureflipClient();
async function handleLogin(userId: string) {
// ... authenticate ...
await client.identify({ user_id: userId, plan: 'pro' });
}
return <button onClick={() => handleLogin('123')}>Log in</button>;
}

Use TestFeatureflipProvider to supply predetermined flag values in tests — no network calls, no initialization delay.

import { TestFeatureflipProvider } from '@featureflip/react-sdk';
import { render, screen } from '@testing-library/react';
test('renders banner when flag is on', () => {
render(
<TestFeatureflipProvider flags={{ 'show-banner': true }}>
<Banner />
</TestFeatureflipProvider>,
);
expect(screen.getByText('New feature available!')).toBeInTheDocument();
});

TestFeatureflipProvider uses FeatureflipClient.forTesting() internally and sets isReady: true immediately.