Expo UI and Router for iOSExpo SDK 57 and later, iOS only
Expo Router

Introduction

Expo Router is an open-source routing library for Universal React Native applications built with Expo.

Expo Router is a file-based router for React Native and web applications. It allows you to manage navigation between screens in your app, allowing users to move seamlessly between different parts of your app's UI, using the same components on multiple platforms (Android, iOS, and web).

Expo Router brings the best file-system routing concepts from the web to a universal application — allowing your routing to work across every platform. When a file is added to the app directory, the file automatically becomes a route in your navigation.

Quick start

We recommend creating a new Expo app using create-expo-app to create a project with Expo Router library already installed and configured:

bun create expo

Now, you can start your project by running:

bun expo start
  • To view your app on a mobile device, we recommend starting with Expo Go. As your application grows in complexity and you need more control, you can create a development build.
  • Open the project in a web browser by pressing W in the Terminal UI. Press A for Android (Android Studio is required), or I for iOS (macOS with Xcode is required).

Resources

Expo Tutorial — A step-by-step guide to build an Expo app that runs on Android, iOS, and web.

Expo Router API reference — API components, hooks, methods, and configuration options.

Expo Router video playlist — A tutorial series from core concepts to more complex navigation flows.

Expo Skills for AI agents

If you use an AI agent, install Expo Skills to teach it file-based navigation patterns:

expo-router — Navigation and routing for Expo Router.

Key features

  • Native: Built on top of React Native Screens, Expo Router navigation is truly native and platform-optimized by default.
  • Shareable: Every screen in your app is automatically deep linkable, making any route in your app shareable with links.
  • Offline-first: Apps are cached and run offline-first, with automatic updates when you publish a new version. Handles all incoming native URLs without a network connection or server.
  • Optimized: Routes are automatically optimized with lazy-evaluation in production, and deferred bundling in development.
  • Iteration: Universal Fast Refresh across Android, iOS, and web, along with artifact memoization in the bundler to keep you moving fast at scale.
  • Universal: Android, iOS, and web share a unified navigation structure, with the ability to drop-down to platform-specific APIs at the route level.
  • Discoverable: Expo Router enables build-time static rendering on web, and universal linking to native. Meaning your app content can be indexed by search engines.

Using a different navigation library

You can use any other navigation library, like React Navigation, in your Expo project.

  • However, if you are building a new app, we recommend using Expo Router for all the features described above.
  • With other navigation libraries, you might have to implement your own strategies for some of these features, such as shareable links or handling web and native navigation in the same project.

If you are looking to use React Native Navigation by Wix, it is not available in Expo Go and is not yet compatible with expo-dev-client. We recommend using createNativeStackNavigator from React Navigation to use Android and iOS native navigation APIs.

Common questions

Expo Router versus Expo versus React Native CLI

Historically, React Native has been non prescriptive about how apps should be built which is similar to using React without a modern web framework. Expo Router is an opinionated framework for React Native, similar to how Remix and Next.js are opinionated frameworks for web-only React.

Expo Router is designed to bring the best architectural patterns to everyone, to ensure React Native is leveraged to its fullest.

  • For example, Expo Router's Async Routes feature enables lazy bundling for everyone.
  • Previously, lazy bundling was only used at Meta to build the Facebook app.

Can I use Expo Router in my existing React Native app?

Yes, Expo Router is the framework for universal React Native apps.

What are the benefits of file-based routing?

  • The file system is a well-known and well-understood concept. The simpler mental model makes it easier to educate new team members and scale your application.
  • The fastest way to onboard new users is by having them open a universal link that opens the app or website to the correct screen depending on if they have the app installed or not. This technique is so advanced that it's usually only available to large companies that can afford to make and maintain the parity between platforms. But with Expo's file-based routing, you can have this feature out of the box!
  • Refactoring is easier to do because you can move files around without having to update any imports or routing components.
  • Expo Router has the ability to statically type routes automatically. This ensures you can only link to valid routes and that you can't link to a route that doesn't exist. Typed Routes also improve refactoring as you'll get type errors if links are broken.
  • Async Routes (bundle splitting) improve development speed, especially in larger projects. They also make upgrades easier as errors are isolated to a single route, meaning you can incrementally update or refactor your app page-by-page rather than all at once (traditional React Native).
  • Deep links always work, for every page. This makes it possible to share links to any content in the app, which is great for promoting your app, collecting bug reports, E2E testing, automating screenshots, and so on.
  • Expo Head uses automatic links to enable deep-native integration. Features like Quick Notes, Handoff, Siri context, and universal links only require configuration setup, no code changes. This enables perfect vertical integration with the entire ecosystem of smart devices that a user has, leading to the types of user experiences that are only possible with universal apps (web ⇄ native).
  • Expo Router has the ability to statically render each page automatically on the web, enabling real SEO and full discoverability of your app's content. This is only possible because of the file-based convention.
  • Expo CLI can infer a lot of information about your application when it follows a known convention. For example, we could implement automatic bundle splitting per route, or automatically generate a sitemap for your website. This is impossible when your app only has a single entry point.
  • Re-engagement features like notifications and home screen widgets are easier to integrate as you can simply intercept the launch and deep link, with query parameters, anywhere in the app.
  • Like on the web, analytics and error reporting can easily be configured to automatically include the route name, which is useful for debugging and understanding user behavior.

Why should I use Expo Router over React Navigation?

Expo Router takes a file-based approach, where routes are derived from your file structure from the app directory.

  • It also has built-in support for typed routes, automatic deep linking, and static rendering for the web.
  • React Navigation lets you define navigators and routes manually in code.
  • Choose whichever model fits your project.

How do I server-render my Expo Router website?

Basic static rendering (SSG) is supported in Expo Router. Server-side rendering currently requires custom infrastructure to set up.

Next steps

Manual installation — Detailed instructions on how to get started and add Expo Router to your existing app.

Router 101 — For information core concepts, notation patterns, navigation layouts, and common navigation patterns, start with Router 101 section.

Example app — See the source code for the example app on GitHub.

Manual installation

Follow the steps below if you have an existing project and want to add Expo Router. For new projects, see the Quick start in the introduction guide.

Prerequisites
Set up your development environment

Make sure your computer is set up for running an Expo app.

Install dependencies

You'll need to install the following dependencies:

bun expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar

The above command will install versions of these libraries that are compatible with the Expo SDK version your project is using.

Setup entry point

For the property main, use the expo-router/entry as its value in the package.json. The initial client file is src/app/_layout.tsx (or app/_layout.tsx if not using the src directory).

{
  "main": "expo-router/entry"
}
Custom entry point to initialize and load side-effects

You can create a custom entry point in your Expo Router project to initialize and load side-effects before your app loads the root layout (src/app/_layout.tsx). Below are some of the common cases for a custom entry point:

  • Initializing global services like analytics, error reporting, and so on.
  • Setting up polyfills
  • Ignoring specific logs using LogBox from react-native
  1. Create a new file in the root of your project, such as index.js. After creating this file, the project structure should look like this:

    src

     app

      _layout.tsx

    index.js

    package.json

    Other project files

  2. Import or add your custom configuration to the file. Then, import expo-router/entry to register the app entry. Remember to always import it last to ensure all configurations are properly set up before the app renders.

    // Import side effects first and services
    
    // Initialize services
    
    // Register app entry through Expo Router
    import 'expo-router/entry';
  3. Update the main property in package.json to point to the new entry file.

    {
      "main": "index.js"
    }

Modify project configuration

Add a deep linking scheme and enable typed routes in your app config:

{
  "expo": {
    "scheme": "your-app-scheme",
    "experiments": {
      "typedRoutes": true
    }
  }
}

If you are developing your app for web, install the following dependencies:

bun expo install react-native-web react-dom

Then, enable Metro web support by adding the following to your app config:

{
  "expo": {
    "web": {
      "bundler": "metro"
    }
  }
}

Modify babel.config.js

If your project has a babel.config.js file, ensure you use babel-preset-expo as the preset. If you don't need any custom Babel configuration, you can delete the file entirely:

module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
  };
};

Configure path aliases

If you are using the src directory, add path aliases to your tsconfig.json so you can use short import paths like @/components/button instead of relative paths:

{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "strict": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}

The @/* alias maps to the src directory in the above example.

Clear bundler cache

After updating the configuration, run the following command to clear the bundler cache:

bun expo start --clear

Update resolutions

If you're upgrading from an older version of Expo Router, ensure you remove all outdated Yarn resolutions or npm overrides in your package.json. Specifically, remove metro, metro-resolver, react-refresh resolutions from your package.json.

Sources

The original Expo docs for this page:

On this page