Noções Básicas do Expo Router
10 exemplos para você começar com o Expo Router - 7 básicos e 3 intermediários. Rotas baseadas em arquivos, _layout.tsx, e o modelo mental comparado ao React Navigation.
Busque em todas as páginas da documentação
10 exemplos para você começar com o Expo Router - 7 básicos e 3 intermediários. Rotas baseadas em arquivos, _layout.tsx, e o modelo mental comparado ao React Navigation.
Crie um aplicativo SDK 57 com o template padrão - ele já vem com Expo Router, TypeScript e o ponto de entrada recomendado.
npx create-expo-app@latest MyRouterApp --template default@sdk-57
cd MyRouterApp
npm install
npx expo install expo-routerConfirme a entrada do roteador e o pin do SDK:
{
"main": "expo-router/entry",
"dependencies": {
"expo": "~57.0.4",
"expo-router": "~6.0.8",
"react": "19.2.3",
"react-native": "0.86.0"
}
}Ferramentas: Estes exemplos visam o Expo SDK 57 (
expo~57.0.4), React Native 0.86.0, e React 19.2.3.
Cada arquivo em app/ se torna um segmento de rota. O nome do arquivo é o caminho - nenhuma configuração central de linking é necessária para telas padrão.
app/
├── index.tsx → /
├── settings.tsx → /settings
├── profile/
│ └── index.tsx → /profile
└── orders/
├── index.tsx → /orders
└── [id].tsx → /orders/:id// app/settings.tsx
import { Text, View } from "react-native";
export default function SettingsScreen() {
return (
<View style={{ flex: 1, padding: 16 }}>
<Text>Configurações</Text>
</View>
);
}app/index.tsx é a rota / - a tela de destino padrão do aplicativoapp/profile/index.tsx → /profile)[id].tsx é um segmento dinâmico - acesse id via useLocalSearchParams()features/ quando a lógica crescerRelacionado: Grupos de Rotas e Organização de
app/-(auth)e(tabs)sem alterar URLs | ../expo-rules/navigation-and-routing-rules/navigation-and-routing-rules.md - convenções de roteamento da equipe
_layout.tsx Raiz Gerencia o NavegadorArquivos _layout.tsx definem navegadores (Stack, Tabs, Drawer) para seu diretório. O layout raiz envolve provedores globais e exporta o navegador de nível superior.
// app/_layout.tsx
import { Stack } from "expo-router";
import { StatusBar } from "expo-status-bar";
export default function RootLayout() {
return (
<>
<StatusBar style="auto" />
<Stack>
<Stack.Screen name="index" options={{ title: "Início" }} />
<Stack.Screen name="settings" options={{ title: "Configurações" }} />
</Stack>
</>
);
}Stack de expo-router é um wrapper baseado em arquivos em torno do @react-navigation/native-stack<Stack.Screen name="settings"> configura a tela que corresponde a app/settings.tsxapp/orders/[id].tsx faz push na pilha raiz, a menos que um _layout.tsx aninhado diga o contrárioRelacionado: Navegação em Pilha (Stack Navigation) - cabeçalhos,
screenOptions, e push/pop | ../architecture-design/feature-sliced-design-for-rn/feature-sliced-design-for-rn.md - mantenhaapp/como a camada de aplicativo FSD
React Navigation constrói uma árvore de navegadores em código. Expo Router constrói a mesma árvore a partir do sistema de arquivos - você troca o createNativeStackNavigator imperativo por nomes de arquivos declarativos.
// React Navigation (árvore imperativa)
const Stack = createNativeStackNavigator();
function AppNavigator() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
);
}// Expo Router (árvore do sistema de arquivos)
app/
├── _layout.tsx → Navegador Stack para esta pasta
├── index.tsx → Tela "Home" (nome derivado do arquivo)
└── settings.tsx → Tela "Settings"| Conceito | React Navigation | Expo Router |
|---|---|---|
| Registro de tela | <Stack.Screen name="Settings" /> | app/settings.tsx existe |
| Navegador aninhado | Navegador dentro de uma tela | app/(tabs)/_layout.tsx |
| Deep link path | Configuração manual de linking | Caminho do arquivo ≈ Caminho da URL |
| Opções de tela | Prop options em Screen | export const options ou <Stack.Screen options> |
useNavigation, useFocusEffect, e APIs de cabeçalho ainda se aplicamsettings.tsx é registrado como "settings" na pilhaRelacionado: Link & href - navegação declarativa sem memorizar nomes de rotas | Rotas Tipadas - segurança de caminho em tempo de compilação
expo-router/entry BootstrapO main do package.json aponta o Metro para a entrada do Expo Router em vez de expo/AppEntry.js ou um App.tsx escrito manualmente.
{
"main": "expo-router/entry",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios"
}
}// Você NÃO precisa de App.tsx - a entrada carrega app/_layout.tsx automaticamente
// app/_layout.tsx é a verdadeira raiz da aplicação
import { Slot } from "expo-router";
export default function RootLayout() {
return <Slot />;
}expo-router/entry registra o componente raiz, manipuladores de links e limites de erroSlot renderiza a rota filha correspondente - use-o quando quiser um layout sem forçar um wrapper Stack/Tabsmain: "expo-router/entry" quebra o roteamento - o bundler não descobrirá as rotas de app/npx expo install expo-router garante que a versão do roteador corresponda aos peers do React Navigation do SDK 57Relacionado: ../project-setup/project-setup-basics/project-setup-basics.md - pin do SDK e layout do template padrão
A sintaxe de colchetes cria segmentos de URL dinâmicos. Leia os parâmetros com useLocalSearchParams - valide antes de usar.
// app/orders/[id].tsx
import { useLocalSearchParams } from "expo-router";
import { Text, View } from "react-native";
export default function OrderDetailScreen() {
const { id } = useLocalSearchParams<{ id: string }>();
return (
<View style={{ flex: 1, padding: 16 }}>
<Text>Pedido #{id}</Text>
</View>
);
}// Navegue programaticamente (imperativo)
import { router } from "expo-router";
router.push({ pathname: "/orders/[id]", params: { id: "42" } });[id] corresponde a um segmento - /orders/42 define id: "42" (sempre strings de URLs)app/users/[userId]/posts/[postId].tsx expõe ambos os parâmetrosRelacionado: Rotas Tipadas - tipos
Hrefgerados para navegação segura de parâmetros | ../expo-rules/navigation-and-routing-rules/navigation-and-routing-rules.md - regras de validação de parâmetros
index.tsx dentro de uma pasta é a tela padrão para esse segmento de caminho - como index.html na web.
app/
├── index.tsx → /
└── orders/
├── _layout.tsx → Stack para /orders/*
├── index.tsx → /orders (lista)
└── [id].tsx → /orders/:id (detalhe)// app/orders/index.tsx
import { Link } from "expo-router";
import { Text, View } from "react-native";
const ORDERS = [{ id: "1" }, { id: "2" }];
export default function OrdersListScreen() {
return (
<View style={{ flex: 1, padding: 16, gap: 12 }}>
{ORDERS.map((order) => (
<Link key={order.id} href={{ pathname: "/orders/[id]", params: { id: order.id } }}>
Pedido #{order.id}
</Link>
))}
</View>
);
}/orders resolve para orders/index.tsx, não orders.tsx - escolha um padrão por recurso_layout.tsx aninhado envolve todos os irmãos naquela pasta (index.tsx e [id].tsx)Relacionado: Redirecionamentos e Rotas de Índice - destino padrão e entrada com autenticação | Link & href -
Linkvsrouter.push
Exporte options de um arquivo de rota ou configure telas em _layout.tsx - ambos alimentam a API de opções de tela do React Navigation.
// app/settings.tsx
import { Stack } from "expo-router";
import { Text, View } from "react-native";
export const options = {
title: "Configurações",
headerLargeTitle: true,
};
export default function SettingsScreen() {
return (
<View style={{ flex: 1, padding: 16 }}>
<Text>Configurações</Text>
</View>
);
}// app/_layout.tsx (alternativa - centralizar chrome)
import { Stack } from "expo-router";
export default function RootLayout() {
return (
<Stack
screenOptions={{
headerShown: true,
animation: "slide_from_right",
}}
/>
);
}screenOptions no navegador define padrões; options por arquivo substitui para uma telaStack.Screen name="settings" options={{...}} em _layout.tsx é equivalente a exportar options de settings.tsxuseNavigation().setOptions() dentro da tela quando os dados carregamRelacionado: Navegação em Pilha (Stack Navigation) - cookbook para cabeçalhos, gestos e modos de apresentação
O template padrão do SDK 57 aninha pilhas sob abas - cada pasta de aba pode fazer push de telas de detalhes sem perder a barra de abas.
app/
├── _layout.tsx
└── (tabs)/
├── _layout.tsx → Navegador Tabs
├── index.tsx → Aba Home
└── orders/
├── _layout.tsx → Stack dentro da aba Orders
├── index.tsx → Lista /orders (raiz da aba)
└── [id].tsx → /orders/:id (push, barra de abas permanece)// app/(tabs)/_layout.tsx
import { Tabs } from "expo-router";
import { Ionicons } from "@expo/vector-icons";
export default function TabLayout() {
return (
<Tabs screenOptions={{ headerShown: false }}>
<Tabs.Screen
name="index"
options={{ title: "Início", tabBarIcon: ({ color }) => <Ionicons name="home" size={24} color={color} /> }}
/>
<Tabs.Screen
name="orders"
options={{ title: "Pedidos", tabBarIcon: ({ color }) => <Ionicons name="list" size={24} color={color} /> }}
/>
</Tabs>
);
}// app/(tabs)/orders/_layout.tsx
import { Stack } from "expo-router";
export default function OrdersStackLayout() {
return (
<Stack>
<Stack.Screen name="index" options={{ title: "Pedidos" }} />
<Stack.Screen name="[id]" options={{ title: "Pedido" }} />
</Stack>
);
}(tabs)/_layout.tsx - cada pasta ou arquivo filho imediato se torna uma abaorders/ - faz push de [id] sobre orders/index enquanto a barra de abas permanece visível(tabs) são um grupo de rotas - eles organizam arquivos sem adicionar /tabs à URLRelacionado: Abas e Gavetas (Tabs & Drawers) - estilo da barra de abas, composição de gavetas | Grupos de Rotas e Organização de
app/- convenções de(tabs)
Grupos de rotas (auth) e (app) separam fluxos de login do shell principal sem alterar os caminhos da URL.
app/
├── _layout.tsx
├── index.tsx → Hub de redirecionamento (veja o artigo sobre redirecionamentos)
├── (auth)/
│ ├── _layout.tsx → Stack para login/cadastro
│ ├── login.tsx → /login
│ └── register.tsx → /register
└── (app)/
├── _layout.tsx → Shell autenticado (abas ou stack)
└── (tabs)/
├── _layout.tsx
└── index.tsx → / (quando logado)// app/(auth)/_layout.tsx
import { Stack } from "expo-router";
export default function AuthLayout() {
return (
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="login" />
<Stack.Screen name="register" />
</Stack>
);
}(auth) e (app) não aparecem em URLs - /login e não /auth/login_layout.tsx raiz ou em index.tsx com <Redirect /> - veja o cookbook de redirecionamentos_layout.tsxRelacionado: Redirecionamentos e Rotas de Índice - entrada com autenticação | ../auth-session/mobile-auth-basics/mobile-auth-basics.md - provedores de sessão
Aplicativos de produção mantêm app/ como uma camada de roteamento - telas, hooks e chamadas de API vivem em features/.
features/
└── orders/
├── index.ts
├── ui/
│ ├── OrdersListScreen.tsx
│ └── OrderDetailScreen.tsx
└── model/
└── useOrder.ts
app/
└── (tabs)/
└── orders/
├── index.tsx → apenas reexporta
└── [id].tsx → apenas reexporta// features/orders/index.ts
export { OrdersListScreen } from "./ui/OrdersListScreen";
export { OrderDetailScreen } from "./ui/OrderDetailScreen";// app/(tabs)/orders/index.tsx
export { OrdersListScreen as default } from "@/features/orders";// app/(tabs)/orders/[id].tsx
export { OrderDetailScreen as default } from "@/features/orders";index.ts - sem importações profundas entre recursosapp/ é a camada do aplicativo, não uma pasta "deus"Relacionado: Melhores Práticas Fundamentais do Expo Router - resumo completo da seção | ../project-setup/folder-structure-for-features/folder-structure-for-features.md - escalando além da árvore inicial
Versões da Pilha: Esta página foi escrita para React 19.2.3, React Native 0.86.0, e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026