Managing App Navigation with Expo Router's File-Based System
Stop fighting with massive navigation config files. Learn how Expo Router's file-based system automates routing and deep linking in React Native.
14 Jun 2026, 02:46 UTC

The Navigation Boilerplate Problem
In traditional React Native development, adding a new screen often requires a three-step ritual: creating the screen component, importing it into a central navigation config, and manually defining the route name and parameters in a Stack or Tab navigator. As an app grows, this central configuration file becomes a merge-conflict magnet and a cognitive burden.
The takeaway is simple: by moving from a config-based navigation model to a file-based model, you can treat your app's directory structure as the source of truth for your routing logic. This eliminates the need for a massive central navigator file and automates deep linking.
How File-Based Routing Works in Expo
Expo Router maps the files in your app/ directory directly to navigation routes. If you create a file at app/settings.js, Expo automatically generates a route accessible at /settings. This approach borrows heavily from web frameworks like Next.js, bringing a predictable URL-like structure to native iOS and Android apps.
Under the hood, Expo Router is a wrapper around React Navigation. You aren't losing the power of the industry-standard navigation library; you are simply changing how those navigators are instantiated. Instead of writing <Stack.Screen /> components manually, the directory nesting defines the hierarchy.
Dynamic Routing and Parameters
Static files handle fixed pages, but most apps need dynamic content (like a user profile or a product page). Expo Router handles this using bracket notation. A file named [id].js acts as a wildcard. When a user navigates to /user/123, the router matches it to the [id].js file and passes 123 as a parameter.
Practical Implementation: A Dynamic Detail View
To implement a dynamic route, ensure you are using Expo SDK 49 or higher. The following example demonstrates a basic setup for a list-to-detail navigation flow.
1. Directory Structure
app/
index.js # The home screen (/)
details/
[id].js # The dynamic detail screen (/details/123)
2. The Home Screen (app/index.js)
Run this in your project root. Use the Link component for type-safe, declarative navigation.
import { Link } from 'expo-router';
import { View, Text } from 'react-native';
export default function Home() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home Screen</Text>
<Link href="/details/42">Go to Item 42</Link>
</View>
);
}
3. The Detail Screen (app/details/[id].js)
Use the useLocalSearchParams hook to extract the dynamic ID from the URL.
import { useLocalSearchParams } from 'expo-router';
import { View, Text } from 'react-native';
export default function Details() {
const { id } = useLocalSearchParams();
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Viewing details for item: {id}</Text>
</View>
);
}
Trade-offs and Limitations
While file-based routing reduces boilerplate, it introduces a new challenge: directory clutter. In a large-scale application with dozens of screens, the app/ folder can become overwhelming. To mitigate this, Expo Router supports Groups. By wrapping a folder name in parentheses, such as (auth)/, you can group related routes (like Login and Sign Up) without adding the group name to the actual URL path.
Additionally, developers transitioning from standard React Navigation may find the lack of a central AppNavigator.js jarring. You no longer have a single place to see every route in the app; instead, you must rely on the file system or the Expo Router's internal route map.
Verifying Your Routes
To verify that your routing is working correctly, especially for deep linking, you can trigger a URI via the terminal. Replace your-scheme with the scheme defined in your app.json:
npx uri-scheme open "your-scheme://details/42" --android
If configured correctly, the app should launch directly to the detail screen for item 42. If the app opens to the home screen instead, check that your file is correctly placed within the app/ directory and that the filename uses the exact [id].js bracket syntax.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.