React Native 20 min read

React Native 2026: Expo vs CLI + React Navigation v7 🚀

Complete React Native guide: Expo (managed/bare), React Native CLI, React Navigation v7 setup, TypeScript, Expo Router, stack/drawer/tab navigators, authentication flows, push notifications, and production deployment.

#React Native #Expo #CLI #React Navigation #TypeScript
Guide React Native

React Native 2026: Expo vs CLI + React Navigation Complete 🚀

React Native powers 85% of top mobile apps with Expo (managed workflow, OTA updates) vs React Native CLI (full native control). React Navigation v7 delivers native stack, tabs, drawer, deep linking, and TypeScript-first navigation. Production-ready with EAS Build, CodePush, and Fastlane.

🎯 Expo vs React Native CLI Decision Matrix

FeatureExpo (Managed)Expo (Bare)React Native CLI
Setup Time5 mins10 mins30-60 mins
Native ModulesExpo SDK onlyAllAll
OTA UpdatesYesYesCodePush
Custom NativeYesYes
Build ServiceEAS BuildEAS/LocalLocal/Fastlane
Team SizeSolo/SmallMediumEnterprise
Learning CurveEasyMediumHard

Quick Start

# Create Expo app
npx create-expo-app@latest MyApp --template
cd MyApp

# Core dependencies
npx expo install react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar
npx expo install @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs
npx expo install react-native-gesture-handler react-native-reanimated

App Entry (App.tsx)

// App.tsx - Expo + React Navigation v7
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { RootSiblingParent } from 'react-native-root-siblings';
import HomeScreen from './src/screens/HomeScreen';
import ProfileScreen from './src/screens/ProfileScreen';

const Stack = createNativeStackNavigator();

export default function App() {
  return (
    <RootSiblingParent>
      <NavigationContainer>
        <Stack.Navigator>
          <Stack.Screen name="Home" component={HomeScreen} />
          <Stack.Screen name="Profile" component={ProfileScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    </RootSiblingParent>
  );
}

Home Screen with Navigation

// src/screens/HomeScreen.tsx
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { useNavigation } from '@react-navigation/native';

export default function HomeScreen() {
  const navigation = useNavigation<any>();

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Welcome to Expo! 🚀</Text>
      <Button
        title="Go to Profile"
        onPress={() => navigation.navigate('Profile', { userId: '123' })}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  title: { fontSize: 24, fontWeight: 'bold', marginBottom: 20 },
});

🛠️ 2. REACT NAVIGATION V7 + TABS + DRAWER

Complete Navigator Setup

// App.tsx - Tabs + Stack + Drawer
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createDrawerNavigator } from '@react-navigation/drawer';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Ionicons } from '@expo/vector-icons';

const Tab = createBottomTabNavigator();
const Drawer = createDrawerNavigator();
const Stack = createNativeStackNavigator();

// Tab Navigator
function TabNavigator() {
  return (
    <Tab.Navigator 
      screenOptions={({ route }) => ({
        tabBarIcon: ({ color, size }) => {
          let iconName: keyof typeof Ionicons.glyphMap;
          if (route.name === 'Home') iconName = 'home';
          else if (route.name === 'Profile') iconName = 'person';
          return <Ionicons name={iconName} size={size} color={color} />;
        },
        headerShown: false,
      })}
    >
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Profile" component={ProfileScreen} />
    </Tab.Navigator>
  );
}

// Main App
export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen 
          name="Main" 
          component={TabNavigator} 
          options={{ headerShown: false }}
        />
        <Stack.Screen name="Auth" component={AuthScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

📱 3. REACT NATIVE CLI (Full Control)

# Global CLI
npm install -g @react-native-community/cli

# Create project
npx react-native@latest init MyApp --version 0.75
cd MyApp

# Navigation dependencies
npm install @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs
npm install react-native-screens react-native-safe-area-context
cd ios && pod install && cd ..

Metro Config (CLI)

// metro.config.js
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');

const config = {};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);

🌐 4. EXPO ROUTER (File-Based Navigation)

# Expo Router (Next.js-style)
npx create-expo-app@latest MyApp --template
npx expo install expo-router

app/ ├── _layout.tsx # Root layout ├── index.tsx # Home screen (/) ├── profile.tsx # /profile └── (tabs)/ ├── _layout.tsx # Tab navigator ├── home.tsx └── profile.tsx

// app/_layout.tsx
import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="index" options={{ title: 'Home' }} />
      <Stack.Screen name="profile" options={{ title: 'Profile' }} />
    </Stack>
  );
}

🔐 5. AUTHENTICATION FLOW

// Auth Navigator
function AuthNavigator() {
  return (
    <Stack.Navigator screenOptions={{ headerShown: false }}>
      <Stack.Screen name="Login" component={LoginScreen} />
      <Stack.Screen name="Register" component={RegisterScreen} />
    </Stack.Navigator>
  );
}

// Root Navigator with Auth Check
function RootNavigator() {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  
  return (
    <NavigationContainer>
      <Stack.Navigator screenOptions={{ headerShown: false }}>
        {isAuthenticated ? (
          <Stack.Screen name="MainTabs" component={TabNavigator} />
        ) : (
          <Stack.Screen name="Auth" component={AuthNavigator} />
        )}
      </Stack.Navigator>
    </NavigationContainer>
  );
}

📲 6. PRODUCTION FEATURES

Push Notifications (Expo)

npx expo install expo-notifications expo-device
// notifications.ts
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});

EAS Build (Production)

# Login to Expo
npx eas login

# Configure build
npx eas build:configure

# Build for stores
eas build --platform all --profile preview
# eas.json
{
  "build": {
    "preview": {
      "distribution": "internal",
      "ios": { "simulator": true }
    },
    "production": {}
  }
}

🎨 7. UI LIBRARY INTEGRATION

# NativeWind (Tailwind CSS)
npx expo install nativewind
npx expo install react-native-reanimated react-native-gesture-handler

# shadcn-native (UI Components)
npx shadcn-native-ui@latest init
npx shadcn-native-ui@latest add button card
// NativeWind components
import { StyledView, StyledText } from 'nativewind';

<StyledView className="flex-1 justify-center items-center bg-gray-100 p-8">
  <StyledText className="text-2xl font-bold text-blue-600 mb-4">
    NativeWind + Expo
  </StyledText>
  <StyledTouchableOpacity className="bg-blue-500 px-8 py-3 rounded-lg">
    <StyledText className="text-white font-semibold">Button</StyledText>
  </StyledTouchableOpacity>
</StyledView>

📊 Performance Comparison

MetricExpo ManagedExpo BareReact Native CLI
Build Time3 mins5 mins15 mins
APK Size25MB18MB15MB
Hot ReloadInstantInstant2-3s
OTA UpdatesYesYesManual
Native AccessLimitedFullFull

🎯 Production Checklist

✅ [] Expo SDK 51 / React Native 0.75 ✅ [] React Navigation v7 (Stack + Tabs + Drawer) ✅ [] TypeScript full-stack ✅ [] NativeWind / shadcn-native UI ✅ [] Expo Router (file-based, optional) ✅ [] EAS Build + OTA updates ✅ [] Push notifications ✅ [] Deep linking ✅ [] Detox testing ✅ [] Sentry crash reporting

🚀 DEPLOYMENT COMMANDS

# Expo (Recommended)
eas build --platform all --profile production
eas submit --platform ios
eas submit --platform android

# CLI (Manual)
npx react-native run-android --variant=release
cd ios && xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -configuration Release

🎯 Final Strategy

Solo/Small Teams → Expo Managed (80%) Medium Teams → Expo Bare (15%) Enterprise → React Native CLI (5%)

Expo + React Navigation v7 = Production mobile apps in 1 day. File-based routing, TypeScript, OTA updates, EAS Build = 90% less native complexity.


Expo: expo.dev | React Navigation: reactnavigation.org

Chat with us