By Malik Chohra
Use React Navigation in Expo (2026 Guide)
Comprehensive guide to React Navigation with Stack, Tab, and Drawer navigators. Includes TypeScript, deep linking, custom headers, and performance optimization.
Mastering React Navigation in Expo
React Navigation is the de facto standard for routing and navigation in React Native applications. With Expo, setting up and configuring navigation becomes even more streamlined. This comprehensive guide covers everything from basic setup to advanced patterns including TypeScript integration, deep linking, and performance optimization.
Whether you're building a simple app with basic navigation or a complex application with nested navigators and deep linking, this guide provides the patterns and best practices you need.
A quick note on terminology: modern Expo projects use Expo Router, a file-based layer built directly on top of React Navigation. You get the same Stack, Tabs, and Drawer navigators, but routes are defined by your folder structure inside app/ rather than wired up by hand. The examples below use Expo Router, with the underlying React Navigation config shown where it matters.
Getting Started
Install React Navigation in your Expo project:
npx expo install @react-navigation/native
npx expo install react-native-screens react-native-safe-area-context
npx expo install @react-navigation/native-stack
npx expo install @react-navigation/bottom-tabs
npx expo install @react-navigation/drawerStack Navigator
The Stack Navigator provides a way to transition between screens where each new screen is placed on top of a stack:
// app/_layout.tsx
import { Stack } from 'expo-router';
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" options={{ title: 'Home' }} />
<Stack.Screen name="details" options={{ title: 'Details' }} />
</Stack>
);
}Tab Navigator
Bottom tab navigation is perfect for primary navigation in mobile apps:
// app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
export default function TabLayout() {
return (
<Tabs>
<Tabs.Screen
name="home"
options={{
title: 'Home',
tabBarIcon: ({ color }) => <Ionicons name="home" size={24} color={color} />,
}}
/>
<Tabs.Screen
name="profile"
options={{
title: 'Profile',
tabBarIcon: ({ color }) => <Ionicons name="person" size={24} color={color} />,
}}
/>
</Tabs>
);
}Drawer Navigator
Drawer navigation provides a hidden menu that slides in from the side, common for apps with many top-level destinations. With Expo Router you declare it the same way as Tabs:
// app/(drawer)/_layout.tsx
import { Drawer } from 'expo-router/drawer';
export default function DrawerLayout() {
return (
<Drawer screenOptions={{ drawerType: 'slide' }}>
<Drawer.Screen name="index" options={{ title: 'Home' }} />
<Drawer.Screen name="settings" options={{ title: 'Settings' }} />
</Drawer>
);
}- Gestures - Users swipe from the edge to open the drawer; it works out of the box with react-native-gesture-handler.
- Custom content - Pass a
drawerContentprop to render your own header, avatar, and menu items.
Nesting Navigators
Real apps almost always nest navigators, a tab bar where one tab contains its own stack, for example. With file-based routing this is simply nested folders: a (tabs) group whose feed tab is a folder containing its own _layout.tsx Stack. Keep nesting shallow where you can, every extra layer makes params and back-behavior harder to reason about.
TypeScript Integration
Type-safe navigation with TypeScript prevents common navigation errors:
// types/navigation.ts
export type RootStackParamList = {
Home: undefined;
Details: { id: string };
Profile: { userId: string };
};
// Usage with type safety
navigation.navigate('Details', { id: '123' }); // ✅ Type safe
navigation.navigate('Details'); // ❌ TypeScript error - missing paramsDeep Linking
Enable deep linking to allow users to navigate directly to specific screens via URLs:
// app.json
{
"expo": {
"scheme": "myapp",
"android": {
"intentFilters": [{
"action": "VIEW",
"data": [{ "scheme": "myapp" }]
}]
}
}
}Custom Headers
Customize navigation headers for branding and functionality:
- Custom header components
- Header buttons and actions
- Dynamic header titles
- Header styling and theming
Lazy Loading
Improve app startup performance with lazy-loaded screens:
const DetailsScreen = lazy(() => import('./screens/Details'));
<Stack.Screen
name="details"
component={DetailsScreen}
options={{ lazy: true }}
/>Performance Optimization
Optimize navigation performance for smooth user experience:
- Enable screen optimization flags
- Use lazy loading for heavy screens
- Optimize animations and transitions
- Implement proper state management
Get Navigation Done Right
For Developers: AI Mobile Launcher includes pre-configured navigation with tabs, stacks, deep linking, and TypeScript support, ready for production.
For Founders: Need a mobile app with professional navigation? Contact AI Mobile Launcher for expert development.