This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

Redirects and rewrites

Edit page

Learn how to redirect and rewrite URLs in Expo Router, in the app and on the server.


You can redirect or rewrite an incoming request to a different URL. Expo Router supports this for both in-app navigation and for server requests.

In-app redirects

Using <Redirect>

You can immediately redirect from a particular screen by using <Redirect>:

import { View, Text } from 'react-native'; import { Redirect } from 'expo-router'; export default function Page() { const { user } = useAuth(); if (!user) { return <Redirect href="/login" />; } return ( <View> <Text>Welcome Back!</Text> </View> ); }

Using useRouter

You can also redirect imperatively with the useRouter hook:

import { Text } from 'react-native'; import { useRouter, useFocusEffect } from 'expo-router'; function MyScreen() { const router = useRouter(); useFocusEffect(() => { // Call the replace method to redirect to a new route without adding to the history. // We do this in a useFocusEffect to ensure the redirect happens every time the screen // is focused. router.replace('/profile/settings'); }); return <Text>My Screen</Text>; }

Server redirects

Use the redirects option of the expo-router config plugin in your app config to redirect routes that no longer exist in your app directory. The server matches each rule against the request URL, not the screen name, and responds with a redirect status code and a Location header.

app.json
{ "plugins": [ [ "expo-router", { "redirects": [ { "source": "/redirect/from/here", "destination": "/to/this/route" }, { "source": "/or/redirect/from/here", "destination": "https://to.this.site" } ] } ] ] }

See RedirectConfig in the API reference for the properties of a redirect rule.

Rules

source and destination are URL paths, not the route files on disk. Do not add the /index suffix for a directory route or +api for an API route.

Permanent redirects

Set permanent to true when the resource has a new permanent URL. Clients should then use destination for all future requests, and can cache the redirect. The default is false, which means the resource is temporarily at a different URL.

app.json
{ "plugins": [ [ "expo-router", { "redirects": [ { "source": "/old-pricing", "destination": "/pricing", "permanent": true } ] } ] ] }

The status code depends on permanent and on the request method:

Request methodpermanent: false (default)permanent: true
GET, HEAD302301
Other methods307308

Dynamic segments

source and destination can use the dynamic route syntax. A segment name that appears in both source and destination keeps its value.

app.json
{ "plugins": [ [ "expo-router", { "redirects": [ { "source": "/redirect/[slug]", "destination": "/target/[slug]" } ] } ] ] }

A segment that only appears in source becomes a query parameter of the destination.

app.json
{ "plugins": [ [ "expo-router", { "redirects": [ { "source": "/redirect/[fruit]/[vegetable]/[meat]", "destination": "/target/[vegetable]/[fruit]" } ] } ] ] }

With the rule above, the server redirects /redirect/apple/carrot/beef to /target/carrot/apple?meat=beef.

A catch-all segment matches the rest of the path.

app.json
{ "plugins": [ [ "expo-router", { "redirects": [ { "source": "/redirect/docs/[...path]", "destination": "/guides/[...path]" } ] } ] ] }

With the rule above, the server redirects /redirect/docs/router/intro to /guides/router/intro.

HTTP methods

To redirect only some HTTP methods, list them in methods. Screen requests use the GET method. The supported values are GET, POST, PUT, DELETE, PATCH, OPTIONS, and HEAD.

app.json
{ "plugins": [ [ "expo-router", { "redirects": [ { "source": "/redirect/[slug]", "destination": "/target/[slug]", "methods": ["POST"] } ] } ] ] }

Server rewrites

Use the rewrites option of the expo-router config plugin to serve one route at another URL. The server handles a request for source as if the client had requested destination. The URL in the browser does not change, and the server does not send a redirect status code.

app.json
{ "plugins": [ [ "expo-router", { "rewrites": [ { "source": "/rewrite/from/here", "destination": "/to/this/route" } ] } ] ] }

See RewriteConfig in the API reference for the properties of a rewrite rule. The rules for redirects also apply to rewrites, with one difference: an external URL is not a valid destination.

Dynamic segments work the same way as in redirects.

Server rules in the app

The app reads the redirects and rewrites rules from the app config at runtime on Android, iOS, and web. It applies them to the initial URL, to incoming deep links, and to every navigation call, such as router.push() or a Link press. This keeps the behavior consistent between a server request and in-app navigation. The in-app behavior differs from the server in the following ways:

  • The app treats a rewrite rule as a redirect rule. Navigation to a rewrite source goes to its destination, and the URL changes.
  • The app ignores permanent and methods. There is no HTTP response in the app.
  • The app opens an external destination with the device's URL handler instead of navigating.
  • The app drops a dynamic segment that only appears in source. It does not add the segment as a query parameter.