Skip to main content

React Native SDK

Use Toggly's React Native SDK in React Native and Expo applications.

Grab the printable React Native cheat sheet (download PDF) — provider setup, hooks, components, storage, offline.

Overview​

The React Native SDK is a modular feature flags solution designed for React Native and Expo applications. It provides React hooks, context providers, and declarative components for easy feature flag management.

Packages​

PackageDescription
@ops-ai/react-native-togglyMain SDK with React hooks and components
@ops-ai/react-native-toggly-coreCore functionality (automatically installed)
@ops-ai/react-native-toggly-storage-asyncAsyncStorage adapter for persistent caching
@ops-ai/react-native-toggly-storage-mmkvMMKV adapter for high-performance storage

Installation​

Main SDK (Required)​

npm install @ops-ai/react-native-toggly
# or
yarn add @ops-ai/react-native-toggly

Storage Adapters (Optional)​

For persistent feature flag caching, install a storage adapter:

AsyncStorage (Recommended for Expo):

npm install @ops-ai/react-native-toggly-storage-async @react-native-async-storage/async-storage

MMKV (Recommended for bare React Native - faster):

npm install @ops-ai/react-native-toggly-storage-mmkv react-native-mmkv
cd ios && pod install

Network State Detection (Optional)​

For automatic offline/online handling:

npm install @react-native-community/netinfo

Quick Start​

Basic Setup with Toggly.io​

import React from 'react';
import { TogglyProvider, Feature, useFeatureFlag } from '@ops-ai/react-native-toggly';
import { createAsyncStorageAdapter } from '@ops-ai/react-native-toggly-storage-async';

// Create storage adapter for persistent caching
const storage = createAsyncStorageAdapter();

function App() {
return (
<TogglyProvider
appKey="your-app-key"
environment="production"
storage={storage}
onError={(error) => {
// Report SDK failures to your app logger, Sentry, or Crashlytics
console.warn('Toggly error:', error);
}}
>
<MyApp />
</TogglyProvider>
);
}

function MyApp() {
const { isEnabled, isLoading } = useFeatureFlag('new-dashboard');

if (isLoading) {
return <LoadingSpinner />;
}

return (
<View>
<Feature featureKey="welcome-banner">
<WelcomeBanner />
</Feature>

{isEnabled && <NewDashboard />}
</View>
);
}

Setup without Toggly.io (Local Feature Flags)​

You can use the SDK without connecting to Toggly.io by providing feature defaults:

import React from 'react';
import { TogglyProvider, Feature } from '@ops-ai/react-native-toggly';

const featureDefaults = {
'new-dashboard': true,
'welcome-banner': true,
'experimental-feature': false,
};

function App() {
return (
<TogglyProvider featureDefaults={featureDefaults}>
<MyApp />
</TogglyProvider>
);
}

TogglyProvider​

The TogglyProvider component wraps your app and provides feature flag context to all child components.

<TogglyProvider
// Required (if using Toggly.io)
appKey="your-app-key"
environment="production"

// Optional
identity="user-123" // Stable user identifier
groups={['beta']} // Memberships used by targeting rules
claims={{ plan: 'pro' }} // String rule attributes
featureDefaults={{ feature1: true }} // Default values for features
storage={storageAdapter} // Storage adapter for caching
refreshInterval={30000} // Auto-refresh interval (ms)
hooks={[analyticsHook]} // Extensibility hooks

// Event callbacks
onReady={() => console.log('Ready')}
onError={(error) => console.error(error)}
onFlagsChanged={(flags) => console.log(flags)}
>
<App />
</TogglyProvider>

Supply these values on the first provider mount, instead of initializing and then calling a refreshing context setter. Startup captures the context before storage or native lifecycle callbacks can trigger a request. Persisted flags and conditional revisions are accepted only for the matching complete context.

An omitted or empty identity keeps the stored/generated device-ID fallback; empty groups/claims add no memberships or attributes. Use the context-update API for later login or membership changes, not as an extra startup step.

Configuration Options​

OptionTypeDescription
appKeystringYour Toggly.io application key
environmentstringEnvironment name (e.g., "production", "staging")
identitystringUnique user identifier for targeted rollouts
groupsstring[]Initial group memberships
claimsRecord<string, string>Initial string rule attributes
featureDefaultsRecord<string, boolean>Default feature flag values
storageTogglyStorageStorage adapter for persistent caching
maxCacheKeysnumber | nullOptional LRU cap for identity-scoped feature-flag cache keys (default: unlimited)
refreshIntervalnumberAuto-refresh interval in milliseconds
hooksHook[]Extensibility hooks for analytics, etc.
onReady() => voidCallback when SDK is initialized
onError(error: Error) => voidCallback when an error occurs
onFlagsChanged(flags: Record<string, boolean>) => voidCallback when flags change

For maxCacheKeys behavior, see Client-side cache limits.

Error reporting and refresh behavior​

Use onError to observe fetch, storage, signature, JWK, and refresh failures:

<TogglyProvider
appKey="your-app-key"
environment="production"
storage={storage}
onError={(error) => {
crashlytics().recordError(error);
}}
>
<App />
</TogglyProvider>

After one successful load, refresh failures preserve the last-known-good effective flags instead of clearing currently rendered UI. Initialization responses and debug state expose the last error, and feature UI updates through the effectiveFlagsChanged event. Feature, useFeatureFlag, and useFeatureGate subscribe to that event automatically.

For the shared reliability contract, see Reliability and Error Handling.

Entity context​

Pass a screen entity per widget or hook — not via setIdentity. See Entity & page context.

React Native is a client: registerContext is local. It does not call PUT sdk/{appKey}/contexts.

import { useTogglyService } from '@ops-ai/react-native-toggly'

type Order = { id: string; status: string }

// Call this hook inside a component under TogglyProvider.
function useOrderBadge() {
const toggly = useTogglyService()
return async (order: Order) => {
toggly.registerContext<Order>('Order', (value) => ({
kind: 'Order', key: value.id,
attributes: { Status: value.status },
}))
return toggly.isFeatureOn('OrderBadge', order, 'Order')
}
}

When a flag depends on an entity, resolve it per evaluation; without context, gates fail closed. setIdentity remains user.

Next Steps​