Skip to Content
Developer GuideReact Native

Supaship React Native SDK — feature flags on iOS and Android

@supashiphq/react-native-sdk mirrors the hooks and provider model of @supashiphq/react-sdk for React Native apps. Feature evaluation uses the same SupaClient stack as @supashiphq/javascript-sdk under the hood.

Package: npm @supashiphq/react-native-sdk · Monorepo: javascript-sdkpackages/react-native

Requirements

  • React ≥ 16.8 (hooks)
  • React Native0.71
  • Client SDK key for the environment you deploy to (never expose a server key in mobile bundles)
  • Peer deps: react, react-native (the package pulls in @supashiphq/javascript-sdk and @supashiphq/react-core)

Installation

pnpm add @supashiphq/react-native-sdk

Quick start

Set toolbar: false in native apps — the dev toolbar is for browsers only.

import { SupaProvider, useFeature, FeaturesWithFallbacks, } from '@supashiphq/react-native-sdk' import { View, Text } from 'react-native' const features = { 'new-header': false, 'theme-config': { mode: 'dark' as const, showLogo: true }, } satisfies FeaturesWithFallbacks export function App() { return ( <SupaProvider config={{ sdkKey: 'your-sdk-key', environment: 'production', features, context: { userId: '123' }, toolbar: false, }}> <Home /> </SupaProvider> ) } function Home() { const { feature: newHeader, isLoading } = useFeature('new-header') if (isLoading) return <Text>Loading…</Text> return <View>{newHeader ? <Text>New</Text> : <Text>Old</Text>}</View> }

Type-safe feature flags

Define flags once, then augment this package so useFeature / useFeatures stay typed:

// features.ts import { FeaturesWithFallbacks, InferFeatures } from '@supashiphq/react-native-sdk' export const FEATURE_FLAGS = { 'new-header': false, 'theme-config': { mode: 'dark' as const, showLogo: true }, } satisfies FeaturesWithFallbacks declare module '@supashiphq/react-native-sdk' { interface Features extends InferFeatures<typeof FEATURE_FLAGS> {} }

Invalid feature keys become TypeScript errors after augmentation.

Use cases

Batch flags with useFeatures

import { useFeatures } from '@supashiphq/react-native-sdk' function Dashboard() { const { features, isLoading } = useFeatures( ['new-header', 'paywall-v2'] as const, { context: { plan: 'pro' } }, ) if (isLoading) return <Text>…</Text> return <Text>{features['paywall-v2'] ? 'Paywall B' : 'Paywall A'}</Text> }

Declarative gate — SupaFeature

import { SupaFeature } from '@supashiphq/react-native-sdk' import { Text } from 'react-native' function Header() { return ( <SupaFeature feature='new-header' loading={<Text>…</Text>} variations={{ true: <Text>New header</Text>, false: <Text>Legacy header</Text>, }} /> ) }

Use normal React Native primitives (View, Text, etc.) as children.

Update context after login — useFeatureContext

import { useFeatureContext } from '@supashiphq/react-native-sdk' import { useEffect } from 'react' function SessionBridge({ userId }: { userId: string | undefined }) { const { updateContext } = useFeatureContext() useEffect(() => { if (userId) updateContext({ userId }) }, [userId, updateContext]) return null }

mergeWithExisting defaults to true, same as the web React SDK.

Advanced — useClient and useQuery

import { useClient, useQuery } from '@supashiphq/react-native-sdk' function RemoteConfig() { const client = useClient() const { data, isLoading } = useQuery(['remote-config'], () => client.getFeature('theme-config').then(theme => ({ theme })), ) if (isLoading || !data) return null return <Text>{JSON.stringify(data.theme)}</Text> }

The option refetchOnWindowFocus keeps its name for API parity with the web SDK; on native it refetches when the app returns to active (see below).

refetchOnWindowFocus and AppState

PlatformWhen refetchOnWindowFocus is true
Web (@supashiphq/react-sdk)visibilitychange / window focus
React NativeAppState transitions to active

Defaults for useFeature / useFeatures limit network traffic unless you opt in.

Sensitive context hashing

If you set sensitiveContextProperties, hashing prefers Web Crypto where available. Some Hermes setups may need a crypto.subtle polyfill; see @supashiphq/javascript-sdk documentation for details.

Unit testing (Jest)

Same pattern as the React SDK: wrap tests with SupaProvider, toolbar={false}, then render your screen.

If Jest resolves react-native in a way that pulls native binaries, map it to a small stub:

// jest.config.js module.exports = { moduleNameMapper: { '^react-native$': '<rootDir>/test/react-native-stub.js', }, }
// test/react-native-stub.js exports.AppState = { addEventListener() { return { remove() {} } }, }
  • React SDK — same hooks and patterns in the browser
  • JavaScript SDK — shared client behavior and network config
Last updated on