This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
This is documentation for the next SDK version. For up-to-date documentation, see the latest version (SDK 57).
Expo Router
A file-based routing library for React Native and web applications.
expo-router is a routing library for React Native and web apps. It enables navigation management using a file-based routing system and provides native navigation components.
Learn about Expo Router basics, navigation patterns, core concepts, and more.
In SDK 56 and later, Expo Router no longer supports importing from external
@react-navigation/*packages in application code. Repoint those imports to the matchingexpo-routerentry points. Run the codemod or follow the SDK 55 to 56 migration guide to update your project.
Installation
To use Expo Router in your project, you need to install. Follow the instructions from the Expo Router's installation guide:
Learn how to install Expo Router in your project.
Configuration in app config
If you are using the default template to create a new project, expo-router's config plugin is already configured in your app config.
Example app.json with config plugin
Configurable properties
Usage
For information core concepts, notation patterns, navigation layouts, and common navigation patterns, start with Router 101 section:
APIs
API
import { useRouter, Tabs, Navigator, Slot } from 'expo-router';
Components
Type: React.Element<BadgeProps>
Type: React.Element<ErrorBoundaryProps>
Type: React.Element<Omit<Omit<StandardUseNavigationBuilderOptions<StackNavigationState<ParamListBase>, ExperimentalStackNavigationOptions, StandardExperimentalStackNavigationEventMap>, 'initialRouteName'> & Omit<object, 'initialRouteName'> & {
unstable_screenErrorBoundary: ComponentType<ErrorBoundaryProps>
}, 'children'> & Partial<Pick<Omit<StandardUseNavigationBuilderOptions<StackNavigationState<ParamListBase>, ExperimentalStackNavigationOptions, StandardExperimentalStackNavigationEventMap>, 'initialRouteName'> & Omit<object, 'initialRouteName'> & {
unstable_screenErrorBoundary: ComponentType<ErrorBoundaryProps>
}, 'children'>>>
Renders the new react-native-screens/experimental native stack.
Sibling to Stack. Native-only — on web it falls back to the standard Stack.
Opt-in per navigator: replace <Stack /> with <ExperimentalStack /> in the
specific layout you want to migrate.
Type: React.Element<LabelProps>
Type: React.Element<LocaleProviderProps>
Type: React.Element<Props>
Type: React.Element<React.FC>
Root style-reset for full-screen React Native web apps with a root <ScrollView /> should use the following styles to ensure native parity. See React Native for Web's root element setup.
Type: React.Element<React.FC>
Type: React.Element<Omit<NavigatorProps<any>, 'children' | 'activityEnabled' | 'activityDefaultThreshold'> & {
activityEnabled: boolean
}>
Renders the currently selected content.
There are actually two different implementations of <Slot/>:
- Used inside a
_layoutas theNavigator - Used inside a
Navigatoras the content
Since a custom Navigator will set the NavigatorContext.contextKey to
the current _layout, you can use this to determine if you are inside
a custom navigator or not.
Type: React.Element<SuspenseFallbackProps>
Type: React.Element<TabRouterOptions>
TabRouter is considered an internal implementation and its behavior may change without a notice between expo-router's version
Type: React.Element<Props>
Type: React.Element<VectorIconProps<NameT>>
Helper component for loading vector icons.
Prefer using the md and sf props on Icon rather than using this component directly.
Only use this component when you need to load a specific icon from a vector icon family.
Example
import { Icon, VectorIcon } from 'expo-router'; import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons'; <Icon src={<VectorIcon family={MaterialCommunityIcons} name="home" />} />
{
getImageSource: (name: NameT, size: number, color: ColorValue) => Promise<ImageSourcePropType | null>
}The family of the vector icon.
Example
import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
Type: React.Element<StackScreenProps>
Type: React.Element<StackScreenBackButtonProps>
Component to configure the back button.
Can be used inside Stack.Screen in a layout or directly inside a screen component.
Example
import { Stack } from 'expo-router'; export default function Layout() { return ( <Stack> <Stack.Screen name="detail"> <Stack.Screen.BackButton displayMode="minimal">Back</Stack.Screen.BackButton> </Stack.Screen> </Stack> ); }
Example
import { Stack } from 'expo-router'; export default function Page() { return ( <> <Stack.Screen.BackButton hidden /> <ScreenContent /> </> ); }
Note: If multiple instances of this component are rendered for the same screen, the last one rendered in the component tree takes precedence.
Deprecated: Use
Stack.Titleinstead.
Type: React.Element<StackTitleProps>
Constants
Type: Context<boolean>
Indicates that descendants are rendered inside a native navigator.
Native navigator integrations should provide true so incompatible nested navigators can fail
before reaching the native view hierarchy.
Type: ImperativeRouter
Type: {
addListener: (eventType: EventType, callback: (event: Payload<EventType>) => void) => () => void,
emit: (type: EventType, event: Payload<EventType>) => void,
enable: () => void,
isEnabled: () => boolean
}
Hooks
Returns route info for a screen it is called from.
UrlObject | undefinedHook to run an effect whenever a route is focused. Similar to
React.useEffect, but the effect re-runs
each time the screen comes into focus, and the optional cleanup function runs when the
screen loses focus — not on unmount. This makes it the right primitive for refetching
data, restarting subscriptions, or resetting transient screen state every time a user
returns to the route.
The passed callback should be wrapped in React.useCallback
to avoid running the effect too often.
voidExample
import { useFocusEffect } from 'expo-router'; import { useCallback } from 'react'; export default function Route() { useFocusEffect( // Callback should be wrapped in `React.useCallback` to avoid running the effect too often. useCallback(() => { // Invoked whenever the route is focused. console.log("Hello, I'm focused!"); // Return function is invoked whenever the route gets out of focus. return () => { console.log('This route is now unfocused.'); }; }, []), ); return </>; }
Returns URL parameters for globally selected route, including dynamic path segments. This function updates even when the route is not focused. Useful for analytics or other background operations that don't draw to the screen.
Route URL example: acme://profile/baconbrix?extra=info.
When querying search params in a stack, opt-towards using
useLocalSearchParams because it will only update when the route is focused.
Note: For usage information, see Local versus global search parameters.
RouteOutputParams<TRoute> & TParamsExample
Hook to get the current focus state of the screen. Returns a true if screen is focused, otherwise false.
This can be used if a component needs to render something based on the focus state.
booleanReturns the result of the loader function for the calling route.
LoaderFunctionResult<T>Example
Returns the URL parameters for the contextually focused route. Useful for stacks where you may push a new screen that changes the query parameters. For dynamic routes, both the route parameters and the search parameters are returned.
Route URL example: acme://profile/baconbrix?extra=info.
To observe updates even when the invoking route is not focused, use useGlobalSearchParams.
Note: For usage information, see Local versus global search parameters.
RouteOutputParams<TRoute> & TParamsExample
Returns the navigation object for the current route. Mirrors the React Navigation
navigation object. Use it to
imperatively access layout-specific functionality like navigation.openDrawer() in a
Drawer layout.
TThe navigation object for the current route.
See: The full navigation API is available directly from
expo-router— no@react-navigation/*install required. For the navigator-dependent functions reference, see navigation dependent functions.
Example
When using nested layouts, you can access higher-order layouts by passing a secondary argument denoting the layout route.
For example, /menu/_layout.tsx is nested inside /app/orders/, you can use useNavigation('/orders/menu/').
Example
If you attempt to access a layout that doesn't exist, an error such as
Could not find parent navigation with route "/non-existent" is thrown.
NavigationContainerRefWithCurrent<RootParamList>The root <NavigationContainer /> ref for the app. The ref.current may be null
if the <NavigationContainer /> hasn't mounted yet.
Returns the currently selected route location without search parameters. For example, /acme?foo=bar returns /acme.
Segments will be normalized. For example, /[id]?id=normal becomes /normal.
stringExample
Prevents the screen from being removed while preventRemove is true and calls callback
with the blocked navigation action.
To continue the blocked navigation action, set preventRemove to false and call the
callback's repeat function. To navigate somewhere else, set preventRemove to false, call
the returned disablePrevention function, and then navigate.
() => voidExample
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(true); usePreventRemove(hasUnsavedChanges, ({ repeat }) => { Alert.alert('Discard changes?', undefined, [ { text: 'Cancel', style: 'cancel' }, { text: 'Discard', style: 'destructive', onPress: () => { setHasUnsavedChanges(false); repeat(); }, }, ]); });
Deprecated: Use
useNavigationContainerRefinstead, which returns a Reactref.
NavigationContainerRef<ParamListBase> | nullReturns the navigation state of the root navigator — the top-level navigator that contains the current screen.
NavigationStateThe current NavigationState of the root navigator.
See: React Navigation's navigation state reference for the shape of the returned object.
Example
import { useRootNavigationState } from 'expo-router'; export default function Route() { const { routes } = useRootNavigationState(); return <Text>{routes[0].name}</Text>; }
Hook to access the route prop of the parent screen anywhere.
TRoute prop of the parent screen.
Hook to get the path for the current route based on linking options.
stringPath for the current route.
Returns the Router object for imperative navigation.
ImperativeRouterExample
import { useRouter } from 'expo-router'; import { Text } from 'react-native'; export default function Route() { const router = useRouter(); return ( <Text onPress={() => router.push('/home')}>Go Home</Text> ); }
Returns a list of selected file segments for the currently selected route. Segments are not normalized,
so they will be the same as the file path. For example, /[id]?id=normal becomes ["[id]"].
RouteSegments<TSegments>Example
useSegments can be typed using an abstract. Consider the following file structure:
- app - [user] - index.tsx - followers.tsx - settings.tsx
This can be strictly typed using the following abstract with useSegments hook:
const [first, second] = useSegments<['settings'] | ['[user]'] | ['[user]', 'followers']>()
Returns the server document data for server-side rendering, including <html>/<body>
attributes and additional nodes to add to <head>/<body> for metadata and assets.
ServerDocumentDataExample
import { useServerDocumentContext } from 'expo-router/html'; export default function Root({ children }) { const { htmlAttributes, bodyAttributes, headNodes, bodyNodes } = useServerDocumentContext(); return ( <html {...htmlAttributes}> <head>{headNodes}</head> <body {...bodyAttributes}> {children} {bodyNodes} </body> </html> ); }
SitemapType | nullMethods
Wraps the screen contents in a React Activity that hides once the screen is buried deep enough
in the stack. Hiding runs effect cleanups and releases resources, but keeps React state, so the
screen looks unchanged when the user navigates back to it.
Must be rendered inside a screen component.
ElementStackRouter is considered an internal implementation and its behavior may change without a notice between expo-router's version
Router<StackNavigationState<ParamListBase>, CommonNavigationAction | StackActionType>This API is unstable and may change between minor releases.
Creates a standard-navigation navigator and
wires it into Expo Router in one step. Use unstable_integrateWithRouter instead if you already
have a navigator from createStandardNavigator.
Props declared in both NavigatorProps and CreateProps are intersected, so incompatible types
produce never rather than a type error at this call.
Component<PropsWithoutRef<PickPartial<Omit<StandardUseNavigationBuilderOptions<State, NavigatorOptions, EventMap>, 'initialRouteName'> & Omit<NavigatorProps, 'initialRouteName'> & Omit<RouterOptions, 'initialRouteName'> & {
unstable_screenErrorBoundary: ComponentType<ErrorBoundaryProps>
}, 'children'>>> & {
Protected: FunctionComponent<ProtectedProps>,
Screen: (props: ScreenProps<NavigatorOptions, State, EventMap>) => null
}Example
import { unstable_createStandardRouterNavigator, TabRouter } from 'expo-router'; export const Tabs = unstable_createStandardRouterNavigator(MyTabsContent, TabRouter);
This API is unstable and may change between minor releases.
Wires an existing standard-navigation
navigator into Expo Router, returning a navigator component (with a .Screen child) usable as a
layout. Use unstable_createStandardRouterNavigator to create and integrate in one step.
Component<PropsWithoutRef<PickPartial<Omit<StandardUseNavigationBuilderOptions<State, NavigatorOptions, EventMap>, 'initialRouteName'> & Omit<NavigatorProps, 'initialRouteName'> & Omit<RouterOptions, 'initialRouteName'> & {
unstable_screenErrorBoundary: ComponentType<ErrorBoundaryProps>
}, 'children'>>> & {
Protected: FunctionComponent<ProtectedProps>,
Screen: (props: ScreenProps<NavigatorOptions, State, EventMap>) => null
}Example
import { createStandardNavigator } from 'standard-navigation'; import { unstable_integrateWithRouter, TabRouter } from 'expo-router'; const navigator = createStandardNavigator(MyTabsContent); export const Tabs = unstable_integrateWithRouter(navigator, TabRouter);
Returns whether a navigation is queued or its state update is pending.
The current screen can remain visible while this returns true if the destination suspends.
navigation.dispatchSync bypasses the queue, and native back gestures never enter it, so this
hook does not report navigation triggered by either one.
Returns false when called outside an Expo Router root.
booleanReturns a navigator that automatically injects matched routes and renders nothing when there are no children.
Return type with children prop optional.
Enables use of other built-in React Navigation navigators and other navigators built with the React Navigation custom navigator API.
Component<PropsWithoutRef<PickPartial<ComponentProps<T>, 'children'>>> & {
Protected: FunctionComponent<ProtectedProps>,
Screen: (props: ScreenProps<TOptions, TState, TEventMap>) => null
}Example
Interfaces
Extends: BasePageEvent
The page rendered as part of a preload (e.g. router.prefetch()) and is not
currently focused. If the user later navigates to this route, the matching
pageFocused will fire then; the preload may also be invalidated or the
route unmounted (pageRemoved) without a focus.
Extends: NavigatorDescriptor<NavigatorOptions>
A standard-navigation descriptor extended with Expo Router route information.
Types
Literal type: union
Acceptable values are: PagePreloadedEvent | PageFocusedEvent | PageBlurredEvent | PageRemoved | ActionDispatchedEvent
Memoized callback containing the effect, should optionally return a cleanup function.
undefined | void | () => void
Navigator-level events emitted by ExperimentalStack. Mirrors the subset of
NativeStackNavigationEventMap that the gamma Stack.Screen lifecycle
callbacks can drive.
Options accepted by ExperimentalStack screens. Mirrors the narrow option
surface of the gamma <Stack.HeaderConfig> component from
react-native-screens/experimental. Anything outside this shape is dropped
with a __DEV__ warning at runtime.
Literal type: union
Acceptable values are: NavigationProp<ParamList, RouteName, NavigatorID, StackNavigationState<ParamList>, ExperimentalStackNavigationOptions, ExperimentalStackNavigationEventMap> | StackActionHelpers<ParamList>
Literal type: union
Acceptable values are: {string}:{string} | //{string}
The main routing type for Expo Router. It includes all available routes with strongly typed parameters. It can either be:
- string: A full path like
/profile/settingsor a relative path like../settings. - object: An object with a
pathnameand optionalparams. Thepathnamecan be a full path like/profile/settingsor a relative path like../settings. The params can be an object of key-value pairs.
An Href can either be a string or an object.
Generic: T
Type: T ? T[href] : string | HrefObject
Returns router object for imperative navigation API.
Example
import { router } from 'expo-router'; import { Text } from 'react-native'; export default function Route() { return ( <Text onPress={() => router.push('/home')}>Go Home</Text> ); }
Created by using a special file called +native-intent.tsx at the top-level of your
project's app directory. It exports redirectSystemPath or legacy_subscribe functions,
both methods designed to handle URL/path processing.
Useful for re-writing URLs to correctly target a route when unique/referred URLs are incoming from third-party providers or stale URLs from previous versions.
See: For more information on how to use
NativeIntent, see Customizing links.
Literal type: union
An item that can be displayed in the header. It can be a button, a menu, spacing, or a custom element.
On iOS 26, when showing items on the right side of the header,
if the items don't fit the available space, they will be collapsed into a menu automatically.
Items with type: 'custom' will not be included in this automatic collapsing behavior.
Acceptable values are: NativeStackHeaderItemButton | NativeStackHeaderItemMenu | NativeStackHeaderItemSpacing | NativeStackHeaderItemCustom
A button item in the header.
Type: SharedHeaderItem extended by:
A custom item to display any React Element in the header.
An item that shows a menu when pressed.
Type: SharedHeaderItem extended by:
An item to add spacing between other items in the header.
Literal type: union
Acceptable values are: NavigationProp<ParamList, RouteName, NavigatorID, StackNavigationState<ParamList>, NativeStackNavigationOptions, NativeStackNavigationEventMap> | StackActionHelpers<ParamList>
Type: Omit<NativeStackScreenProps<ParamList, RouteName, NavigatorID>, 'route'> extended by:
Type: Pick<StackNavigationState<ParamListBase>, 'index' | 'routes'>
The navigator-level state consumed by NativeStackView.
Routes after index are preloaded and rendered natively-detached.
Literal type: union
The list of input keys will become optional, everything else will remain the same.
Literal type: union
Acceptable values are: ./{string} | ../{string} | '..'
Type: Exclude<Extract[pathname], RelativePathString | ExternalPathString>
Literal type: string
Whether a screen was declared in the layout (<Screen>/<NativeTabs.Trigger>)
or inferred from the filesystem.
Acceptable values are: 'layout' | 'filesystem'
Type: boolean or object shaped as below:
(name, params) => string | undefined
string | undefinedType: Record<string, {
canPreventDefault: boolean,
data: object | undefined
}>
Type: DefaultNavigatorOptions<ParamListBase, string | undefined, State, NavigatorOptions, EventMap, any>