React Native vs Expo: Mobile Development Guide for Web Developers (2026)
React Native vs Expo compared for 2026. Learn when to use bare React Native vs Expo managed workflow, Expo SDK 52 new architecture, EAS Build, and how to migrate from web React to mobile.
React Native vs Expo: Mobile Development Guide for Web Developers (2026)
If you already build React apps for the web, React Native is the fastest path to mobile. But the first decision youβll face is whether to use bare React Native or Expo β and it matters more than youβd think. This guide gives web developers the context to make the right call in 2026.
Whatβs the Difference?
React Native is the core framework from Meta. It compiles JavaScript/TypeScript to native iOS and Android components. To use it directly, you need Xcode (macOS only) for iOS and Android Studio for Android.
Expo is a platform built on top of React Native that handles tooling, native modules, and infrastructure. Think of it like Next.js for React β it adds conventions, tools, and managed services, but the underlying runtime is still React Native.
| React Native (bare) | Expo Managed | Expo Bare | |
|---|---|---|---|
| Setup complexity | High | Low | Medium |
| iOS build without Mac | No | Yes (EAS) | Yes (EAS) |
| Customizable native code | Full | Limited | Full |
| Native module support | All | Expo SDK only | All |
| Over-the-air updates | Manual | Expo Updates | Expo Updates |
| File-based routing | Manual | Expo Router | Expo Router |
| Who itβs for | Advanced teams, custom native | Most new projects | Expo start, custom later |
Expo Managed Workflow: Where to Start
For most web developers building their first React Native app, start with Expo managed workflow. You get:
- No Xcode or Android Studio required on day 1
- The Expo Go app for instant testing on your physical device
- Pre-configured TypeScript, linting, metro bundler
- A large SDK of pre-built native modules (camera, maps, notifications, biometrics)
npx create-expo-app@latest my-app --template
cd my-app
npx expo start
Scan the QR code with Expo Go on your phone β your app runs immediately.
File-Based Routing with Expo Router
Expo Router brings Next.js-style file-based routing to React Native. If you know Next.js App Router, this feels immediately familiar.
app/
βββ _layout.tsx β Root layout (like layout.tsx in Next.js)
βββ index.tsx β Home screen (/)
βββ about.tsx β About screen (/about)
βββ (tabs)/
βββ _layout.tsx β Tab bar layout
βββ home.tsx
βββ profile.tsx
// app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router'
import { MaterialIcons } from '@expo/vector-icons'
export default function TabLayout() {
return (
<Tabs screenOptions={{ tabBarActiveTintColor: '#007AFF' }}>
<Tabs.Screen
name="home"
options={{
title: 'Home',
tabBarIcon: ({ color }) => (
<MaterialIcons name="home" size={24} color={color} />
),
}}
/>
<Tabs.Screen
name="profile"
options={{
title: 'Profile',
tabBarIcon: ({ color }) => (
<MaterialIcons name="person" size={24} color={color} />
),
}}
/>
</Tabs>
)
}
// app/index.tsx
import { View, Text, Pressable } from 'react-native'
import { Link, useRouter } from 'expo-router'
export default function Home() {
const router = useRouter()
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 24, fontWeight: 'bold' }}>Welcome</Text>
{/* Link component works like Next.js Link */}
<Link href="/about">
<Text>Go to About</Text>
</Link>
{/* Programmatic navigation */}
<Pressable onPress={() => router.push('/profile')}>
<Text>View Profile</Text>
</Pressable>
</View>
)
}
Key Differences from Web React
No CSS β Use StyleSheet
import { StyleSheet, View, Text } from 'react-native'
export default function Card({ title, subtitle }: { title: string; subtitle: string }) {
return (
<View style={styles.card}>
<Text style={styles.title}>{title}</Text>
<Text style={styles.subtitle}>{subtitle}</Text>
</View>
)
}
const styles = StyleSheet.create({
card: {
backgroundColor: 'white',
borderRadius: 12,
padding: 16,
marginVertical: 8,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3, // Android shadow
},
title: {
fontSize: 18,
fontWeight: '600',
color: '#1a1a1a',
},
subtitle: {
fontSize: 14,
color: '#6b7280',
marginTop: 4,
},
})
Or use NativeWind for Tailwind-like classes:
npm install nativewind tailwindcss
import { View, Text } from 'react-native'
export default function Card({ title }: { title: string }) {
return (
<View className="bg-white rounded-xl p-4 my-2 shadow-sm">
<Text className="text-lg font-semibold text-gray-900">{title}</Text>
</View>
)
}
Touch Instead of Click
import { Pressable, TouchableOpacity } from 'react-native'
// Pressable (recommended in React Native 0.70+)
<Pressable
onPress={handlePress}
onLongPress={handleLongPress}
style={({ pressed }) => [
styles.button,
pressed && styles.buttonPressed,
]}
>
<Text>Press Me</Text>
</Pressable>
Scrollable Containers
On mobile, div overflow doesnβt scroll. Use ScrollView or FlatList:
import { FlatList } from 'react-native'
// FlatList for long lists β only renders visible items
<FlatList
data={items}
keyExtractor={item => item.id}
renderItem={({ item }) => <ItemCard item={item} />}
onEndReached={loadMore}
onEndReachedThreshold={0.5}
/>
Expo SDK 52: The New Architecture
React Nativeβs New Architecture (Fabric renderer + TurboModules + JSI) has been in development for years. With Expo SDK 52 and React Native 0.76, itβs enabled by default.
What the New Architecture Changes
Before (Old Architecture):
- JavaScript β Native communication via JSON serialization over a bridge
- Asynchronous only β no synchronous calls
- Layout calculated on native thread, JS on its own thread
After (New Architecture):
- JSI (JavaScript Interface) β direct C++ bindings, synchronous access
- TurboModules β native modules load on demand, not all at startup
- Fabric β concurrent rendering, interop with Reactβs scheduler
In practice, youβll notice:
- 20-40% faster list scrolling
- Better animation performance
- Faster startup (TurboModules lazy-load)
- More reliable gesture handling
// SDK 52: enable new architecture in app.json
{
"expo": {
"experiments": {
"newArchEnabled": true // default in SDK 52
}
}
}
EAS Build: iOS Without a Mac
Expo Application Services (EAS) Build is a cloud build service. You push your code; Expoβs servers compile it and deliver .ipa (iOS) and .apk/.aab (Android) files.
npm install -g eas-cli
eas login
eas build:configure
// eas.json
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal",
"android": { "buildType": "apk" }
},
"production": {
"autoIncrement": true
}
}
}
# Build for iOS (no Mac required)
eas build --platform ios --profile production
# Build for Android
eas build --platform android --profile production
# Submit to App Store and Play Store
eas submit --platform ios
eas submit --platform android
EAS Update: Over-the-Air Updates
eas update --branch production --message "Fix checkout bug"
OTA updates let you push JavaScript and asset changes without going through App Store review. Only use for bug fixes β Appleβs guidelines prohibit using OTA updates to change app functionality significantly.
When to Use Bare React Native
Managed Expo has limits. Youβll need to eject to bare workflow (or start bare) when:
-
Custom native modules β third-party SDKs that arenβt in Expo SDK (some payment SDKs, custom Bluetooth, proprietary analytics)
-
Deep native customization β custom app extensions, widgets, watch apps, carplay
-
Performance-critical code β custom C++ bridges, custom renderers
# Start bare from scratch
npx create-expo-app@latest my-app --template bare-minimum
# Or eject from managed
npx expo prebuild # Generates ios/ and android/ folders
Once you have ios/ and android/ folders, you can write native code and use any React Native library. You still get most Expo tools (EAS Build, EAS Update, Expo Router).
React Native vs Flutter vs Capacitor
| React Native/Expo | Flutter | Capacitor | |
|---|---|---|---|
| Language | JavaScript/TS | Dart | JavaScript/TS |
| Renders | Native components | Custom canvas | WebView |
| Web support | Experimental | Yes | Native web |
| Performance | Good | Excellent | Good |
| Learning curve | Low (React devs) | Medium | Very low |
| Hot reload | Yes | Yes | Yes |
Choose React Native/Expo if: You know React and want mobile. Choose Flutter if: You want the best performance and donβt mind learning Dart. Choose Capacitor if: You want to wrap an existing web app as a mobile app with minimal changes.
Debugging Tools
Expo DevTools
npx expo start
# Press 'm' in terminal to open Expo Dev Menu on device
# Or shake your device
From the dev menu: inspect component tree, network requests, performance monitor.
React Native Debugger
A standalone DevTools app that combines Chrome DevTools, Redux DevTools, and React DevTools in one window.
brew install --cask react-native-debugger # macOS
# Or download from GitHub: jhen0409/react-native-debugger
Flipper (Metaβs Debug Tool)
brew install flipper # macOS
Flipper connects to running apps and shows:
- Network requests (Hermes-based apps)
- Layout inspector with component highlight
- Crash reporter
- Custom plugins
Expo Snack: Browser-Based Prototyping
Expo Snack is a browser-based React Native sandbox β no installation needed. Great for sharing reproducible examples and prototyping UI components.
Migration Path: Web React β React Native
Most React concepts transfer directly. Hereβs the translation:
| Web React | React Native |
|---|---|
<div> | <View> |
<p>, <h1>, <span> | <Text> |
<img> | <Image> |
<input> | <TextInput> |
<button> | <Pressable> |
| CSS flexbox | StyleSheet flexbox (default, same properties) |
onClick | onPress |
<a> | <Link> (Expo Router) |
useState, useEffect | Same |
fetch | Same |
| Context API, Zustand, Jotai | Same |
Your state management, API calls, and business logic transfer unchanged. You rewrite only the UI layer.
Summary
For web developers entering mobile in 2026:
- Start with Expo (managed workflow) β youβll have a working app on your phone in 20 minutes
- Use Expo Router β file-based routing feels like home if you know Next.js
- Expo SDK 52 + New Architecture β enabled by default, meaningfully better performance
- EAS Build β iOS builds without a Mac, App Store submission from CI/CD
- Eject to bare only when you need custom native modules or deep customization
The React knowledge you have today transfers directly. The main investment is learning the mobile-specific components (View, Text, FlatList) and understanding how touch, gestures, and platform differences work. For most apps, youβll be productive in React Native within a week.
For debugging your React Native apps, check out React Native Debugger and Expo Snack tools on DevPlaybook.
50 CLI Commands That Save Hours Every Week
The exact Git shortcuts, file search tricks, Docker commands, and productivity hacks that senior developers use daily. Compiled from 5+ years of shipping production code.
- Git mastery (10 cmds)
- File & search wizardry
- Docker & DevOps tricks
- Process & network tools
- Productivity boosters
- macOS & Linux install guide
No spam. 1 email/week max. Unsubscribe anytime.
Found this guide useful? Check out our free developer tools.
Affiliate disclosure: Some links below are affiliate links β we may earn a small commission at no extra cost to you. Learn more.
Recommended Tools & Resources
DigitalOcean
$200 credit for new users. Simple, affordable cloud hosting for developers.
GitHub Student Pack
Free access to 100+ developer tools. Perfect for students and new devs.
Vercel
Deploy frontend apps instantly. Free tier is generous for side projects.
DevPlaybook Products
Boilerplates, scripts & AI toolkits to 10x your dev workflow.