# Expo Router in React Native: File-Based Navigation Complete Guide > Master Expo Router for React Native with this complete tutorial covering file-based routing, layouts, dynamic routes, typed navigation, and advanced patterns like modals and tabs in 2026. - Published: 2026-04-18 - Updated: 2026-04-18 - Author: SharpSkill - Tags: react-native, expo, expo-router, navigation, mobile-development, tutorial - Reading time: 9 min --- Expo Router brings file-based routing to React Native, replacing manual navigation configuration with a convention-driven approach inspired by Next.js. Starting with Expo SDK 55 and Expo Router v6, building cross-platform navigation for Android, iOS, and web requires nothing more than creating files in the right directory. > **Quick Setup** > > New Expo projects ship with Expo Router pre-configured. Run `npx create-expo-app@latest --template default@sdk-55` to start with file-based routing out of the box. Existing projects can add it by installing `expo-router` and updating the entry point. ## How File-Based Routing Works in Expo Router Every file inside the `app` directory automatically becomes a route. The file path maps directly to the URL path, eliminating the need for a centralized navigation configuration. A file at `app/settings.tsx` creates a `/settings` route, while `app/profile/edit.tsx` maps to `/profile/edit`. This approach offers three key advantages over traditional React Navigation setup: - **Zero configuration**: routes exist the moment a file is created - **Automatic deep linking**: every screen gets a URL, enabling sharing and testing - **Type-safe navigation**: TypeScript knows which routes exist at compile time ```typescript // app/index.tsx import { View, Text, StyleSheet } from 'react-native' import { Link } from 'expo-router' export default function HomeScreen() { return ( Welcome {/* Link maps directly to file path */} Open Settings Edit Profile ) } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', padding: 24 }, title: { fontSize: 28, fontWeight: 'bold', marginBottom: 16 }, link: { fontSize: 16, color: '#61DAFB', marginTop: 12 }, }) ``` The `Link` component handles navigation across all platforms. On the web, it renders an anchor tag with proper href attributes for SEO. On native platforms, it triggers stack-based navigation. ## Project Structure and Layout Files Expo Router uses `_layout.tsx` files to define navigation containers. Each directory can have its own layout, creating nested navigation hierarchies. The root layout wraps the entire app, while nested layouts control specific sections. A typical project structure looks like this: ```text app/ _layout.tsx # Root layout (Stack or custom) index.tsx # Home screen (/) (tabs)/ # Tab group (parentheses = route group) _layout.tsx # Tab navigator home.tsx # /home tab search.tsx # /search tab profile.tsx # /profile tab settings/ _layout.tsx # Settings stack layout index.tsx # /settings notifications.tsx # /settings/notifications privacy.tsx # /settings/privacy ``` Route groups — directories wrapped in parentheses — organize files without affecting the URL. The `(tabs)` directory above creates a tab navigator, but the URLs remain `/home`, `/search`, and `/profile` rather than `/tabs/home`. ```typescript // app/_layout.tsx import { Stack } from 'expo-router' export default function RootLayout() { return ( ) } ``` The root layout also serves as the place to load fonts, initialize providers, and configure global settings — replacing the traditional `App.tsx` entry point. ## Building Tab Navigation with Expo Router Tab navigation requires a `_layout.tsx` file inside a route group. Expo Router v6 introduces `NativeTabs` for platform-specific tab experiences, but the standard `Tabs` component from Expo Router covers most use cases. ```typescript // app/(tabs)/_layout.tsx import { Tabs } from 'expo-router' import { Ionicons } from '@expo/vector-icons' export default function TabLayout() { return ( ( ), }} /> ( ), }} /> ( ), }} /> ) } ``` Each tab screen file exports a standard React component. The tab bar icon, label, and badge are configured through the `options` prop in the layout. ## Dynamic Routes and Route Parameters Dynamic segments use square brackets in the filename. A file named `[id].tsx` matches any single segment, while `[...slug].tsx` catches all remaining segments. ```typescript // app/product/[id].tsx import { View, Text, StyleSheet } from 'react-native' import { useLocalSearchParams, Stack } from 'expo-router' export default function ProductScreen() { // Extract the dynamic parameter from the URL const { id } = useLocalSearchParams<{ id: string }>() return ( Product Details ID: {id} ) } const styles = StyleSheet.create({ container: { flex: 1, padding: 24 }, heading: { fontSize: 24, fontWeight: 'bold', marginBottom: 8 }, id: { fontSize: 16, color: '#888' }, }) ``` Navigating to `/product/42` renders this screen with `id` set to `"42"`. The `useLocalSearchParams` hook provides typed access to all route parameters. For catch-all routes, `[...slug].tsx` captures entire path segments: ```typescript // app/docs/[...slug].tsx import { useLocalSearchParams } from 'expo-router' export default function DocsScreen() { // /docs/getting-started/installation → slug = ['getting-started', 'installation'] const { slug } = useLocalSearchParams<{ slug: string[] }>() return } ``` ## Typed Routes for Compile-Time Safety Expo Router generates route types automatically when `typed routes` is enabled. This catches broken links at compile time rather than at runtime. Enable typed routes in `app.json`: ```json { "expo": { "experiments": { "typedRoutes": true } } } ``` Once enabled, the `href` prop on `Link` and the argument to `router.push()` only accept valid route strings: ```typescript // app/checkout.tsx import { router } from 'expo-router' function handleCheckout(cartId: string) { // TypeScript validates this route exists router.push(`/product/${cartId}`) // This would cause a compile error if /nonexistent doesn't exist // router.push('/nonexistent') } ``` Typed routes pair well with `useLocalSearchParams`. The generated types ensure parameter names match between the route definition and the consuming component, preventing subtle bugs that surface only when navigating to a specific screen. ## Modal Screens and Presentation Options Modals in Expo Router are regular screens configured with `presentation: 'modal'` in the layout. This approach keeps the file-based convention intact — a modal is just another route. ```typescript // app/_layout.tsx import { Stack } from 'expo-router' export default function RootLayout() { return ( {/* Modal screen slides up from the bottom */} ) } ``` ```typescript // app/create-post.tsx import { View, TextInput, Button, StyleSheet } from 'react-native' import { router } from 'expo-router' import { useState } from 'react' export default function CreatePostModal() { const [title, setTitle] = useState('') const handleSubmit = () => { // Submit logic here router.back() // Dismiss the modal } return (