Skip to main content

React Native SDK Usage

Learn how to integrate Superflag into your React Native or Expo application.

Setup Provider

Wrap your app with SuperflagProvider at the root level:
App.tsx
import { SuperflagProvider } from '@superflag-sh/react-native'

export default function App() {
  return (
    <SuperflagProvider clientKey={process.env.EXPO_PUBLIC_SUPERFLAG_CLIENT_KEY}>
      <YourApp />
    </SuperflagProvider>
  )
}

Using Flags

Basic Usage

Use the useFlag hook to access flag values:
import { useFlag } from '@superflag-sh/react-native'
import { View, Text } from 'react-native'

function MyScreen() {
  const showNewFeature = useFlag('new-feature', false)

  return (
    <View>
      {showNewFeature && <NewFeatureComponent />}
    </View>
  )
}

Type-Safe Flags

Use TypeScript generics for type-safe flag values:
import { useFlag } from '@superflag-sh/react-native'

function ThemeScreen() {
  // Boolean flag
  const darkMode = useFlag<boolean>('dark-mode', false)

  // String flag
  const theme = useFlag<string>('theme', 'light')

  // Number flag
  const fontSize = useFlag<number>('font-size', 16)

  // JSON flag
  const config = useFlag<{ color: string; size: number }>('ui-config', {
    color: '#3B82F6',
    size: 14
  })

  return (
    <Text style={{ color: config.color, fontSize: config.size }}>
      Theme: {theme}
    </Text>
  )
}

Checking SDK Status

Use useFlags to check if the SDK is ready:
import { useFlags } from '@superflag-sh/react-native'
import { ActivityIndicator, View, Text } from 'react-native'

function MyScreen() {
  const { ready, loading, status, error } = useFlags()

  if (loading) {
    return <ActivityIndicator />
  }

  if (error) {
    return <Text>Error: {error}</Text>
  }

  if (!ready) {
    return <View />
  }

  return <YourContent />
}

Provider Props

Configure the provider with these optional props:
PropTypeDefaultDescription
clientKeystringenv varPublic client key (pub_*)
ttlSecondsnumber60Cache time-to-live in seconds

Custom TTL

Control how long flags are cached:
// Cache for 5 minutes
<SuperflagProvider clientKey="pub_..." ttlSeconds={300}>
  <App />
</SuperflagProvider>

Caching Behavior

The SDK uses AsyncStorage for persistent caching:
  1. First launch: Fetches flags from API, stores in AsyncStorage
  2. Subsequent launches:
    • Shows cached flags immediately
    • Checks for updates in background using ETag
    • Only downloads if config changed (HTTP 304 if unchanged)
  3. Cache expiry: After ttlSeconds, forces a fresh fetch
This means your app loads instantly with cached flags while staying up-to-date.

Environment Variables

Expo

.env
EXPO_PUBLIC_SUPERFLAG_CLIENT_KEY=pub_prod_...
Then access in your code:
<SuperflagProvider clientKey={process.env.EXPO_PUBLIC_SUPERFLAG_CLIENT_KEY}>

React Native with react-native-config

  1. Install react-native-config:
    npm install react-native-config
    
  2. Create .env file:
    .env
    SUPERFLAG_CLIENT_KEY=pub_prod_...
    
  3. Use in code:
    import Config from 'react-native-config'
    
    <SuperflagProvider clientKey={Config.SUPERFLAG_CLIENT_KEY}>
    
Always use public keys (pub_*) in mobile apps. Never use SDK keys (sdk_*).

Status Values

The status field from useFlags() can be:
StatusDescription
idleInitial state before fetching
loadingFetching flags from API
readyFlags loaded successfully
errorFailed to load flags
rate-limitedMonthly quota exceeded

Error Handling

The SDK never crashes your app. Errors are returned in the state:
function MyScreen() {
  const { status, error } = useFlags()

  if (status === 'error') {
    console.error('Failed to load flags:', error)
    // App continues with fallback values
  }

  if (status === 'rate-limited') {
    console.warn('Rate limited - using cached flags')
  }

  // Your component code...
}

Offline Support

The SDK works offline using cached flags:
import { useFlag, useFlags } from '@superflag-sh/react-native'
import NetInfo from '@react-native-community/netinfo'

function MyScreen() {
  const [isOnline, setIsOnline] = useState(true)
  const feature = useFlag('feature', false)
  const { lastFetchedAt } = useFlags()

  useEffect(() => {
    const unsubscribe = NetInfo.addEventListener(state => {
      setIsOnline(state.isConnected ?? false)
    })
    return unsubscribe
  }, [])

  return (
    <View>
      {!isOnline && <Text>Offline mode - using cached flags</Text>}
      {feature && <FeatureComponent />}
    </View>
  )
}

Performance Tips

Avoid Re-renders

import { memo } from 'react'
import { useFlag } from '@superflag-sh/react-native'

const ExpensiveComponent = memo(function ExpensiveComponent() {
  const config = useFlag('config', { items: 10 })

  // This only re-renders when config actually changes
  return <HeavyList items={config.items} />
})

Conditional Rendering

function OptionalFeature() {
  const enabled = useFlag('optional-feature', false)

  // Early return to avoid rendering
  if (!enabled) return null

  return <ExpensiveFeatureComponent />
}

Next Steps