Grupos de Rotas e Organização de app/
Convenções de pastas (auth), (tabs) e privadas. Grupos de rotas mantêm árvores app/ grandes navegáveis sem poluir URLs ou caminhos de deep-link.
Busque em todas as páginas da documentação
app/Convenções de pastas (auth), (tabs) e privadas. Grupos de rotas mantêm árvores app/ grandes navegáveis sem poluir URLs ou caminhos de deep-link.
Cartão de receita de referência rápida - pronto para copiar e colar.
app/
├── _layout.tsx # Provedores raiz + navegador superior
├── index.tsx # Hub de redirecionamento de entrada
├── (auth)/
│ ├── _layout.tsx # Pilha de autenticação (sem cabeçalho)
│ ├── login.tsx # /login
│ └── register.tsx # /register
├── (app)/
│ ├── _layout.tsx # Shell de guarda autenticado
│ └── (tabs)/
│ ├── _layout.tsx
│ ├── index.tsx # /
│ └── settings.tsx # /settings
├── (modals)/
│ ├── _layout.tsx # presentation: modal
│ └── compose.tsx # /compose
└── _components/ # Privado - NÃO é uma rota
└── ScreenChrome.tsx// app/(app)/_layout.tsx - shell de autenticação mínimo
import { Redirect, Stack } from "expo-router";
import { useSession } from "@/features/auth";
export default function AppShellLayout() {
const { session, isLoading } = useSession();
if (isLoading) return null;
if (!session) return <Redirect href="/login" />;
return <Stack screenOptions={{ headerShown: false }} />;
}Quando usar isso:
presentation: "modal"/tabs em cada URL_components/ ao lado dos layoutsUma árvore com formato de produção com grupo de autenticação, shell de aplicativo, abas, modais e pastas privadas.
// app/_layout.tsx
import { Stack } from "expo-router";
import { AppProviders } from "@/app-providers";
export default function RootLayout() {
return (
<AppProviders>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="index" />
<Stack.Screen name="(auth)" />
<Stack.Screen name="(app)" />
<Stack.Screen name="(modals)" options={{ presentation: "modal" }} />
</Stack>
</AppProviders>
);
}// app/(auth)/_layout.tsx
import { Stack } from "expo-router";
export default function AuthLayout() {
return (
<Stack screenOptions={{ headerShown: false, animation: "fade" }}>
<Stack.Screen name="login" />
<Stack.Screen name="register" />
</Stack>
);
}// app/(modals)/_layout.tsx
import { Stack } from "expo-router";
export default function ModalsLayout() {
return (
<Stack
screenOptions={{
presentation: "modal",
headerShown: true,
}}
/>
);
}// app/(app)/(tabs)/_layout.tsx
import { Tabs } from "expo-router";
export default function TabsLayout() {
return (
<Tabs>
<Tabs.Screen name="index" options={{ title: "Home" }} />
<Tabs.Screen name="settings" options={{ title: "Settings" }} />
</Tabs>
);
}// app/_components/LoadingGate.tsx - importar de layouts; nunca roteado
import { ActivityIndicator, View } from "react-native";
export function LoadingGate() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<ActivityIndicator />
</View>
);
}Mapa de URL (grupos omitidos do caminho):
/login → (auth)/login.tsx
/register → (auth)/register.tsx
/ → (app)/(tabs)/index.tsx
/settings → (app)/(tabs)/settings.tsx
/compose → (modals)/compose.tsx| Padrão | Impacto na URL | Propósito |
|---|---|---|
(auth)/login.tsx | /login | Nome do grupo omitido da URL |
(tabs)/index.tsx | / | Organizar arquivos de abas |
[id].tsx | /:id | Segmento dinâmico (não é um grupo) |
_layout.tsx | - | Navegador para a pasta |
_components/ | - | Pasta privada (prefixo underscore) |
(app)/(tabs)/ é válido - ambos os nomes são removidos da URL_layout.tsx por pasta para navegadoresapp/ features/
├── apenas roteamento e layouts ├── lógica de negócios
├── re-exportações ├── hooks e API
├── redirecionamentos └── telas de UI
└── _components/ (privado)(auth) para login, (app) para shell logado, (modals) para overlaysapp/(app)/(tabs)/orders/ mapeia para features/orders/index.tsx raiz leve - apenas hub de redirecionamento; veja Redirecionamentos e Rotas de Índiceapp/(app)/(tabs)/orders/[id].tsx é suficiente; caminhos mais profundos sinalizam hora de refatorarapp/(tabs)/
├── _layout.tsx
├── _components/
│ └── TabIcon.tsx
├── index.tsx
└── profile.tsx_prefixo marca arquivos/pastas não roteáveis - Expo Router os ignora para geração de URL_components/ - não os coloque em features/ a menos que sejam reutilizados+html.tsx, +not-found.tsx são arquivos especiais - aprenda seus papéis antes de personalizar web/not-found// app/_layout.tsx - registro explícito impede descoberta automática ambígua
<Stack>
<Stack.Screen name="(auth)" />
<Stack.Screen name="(app)" />
</Stack><Stack.Screen name="(auth)" /> explícito documenta segmentos de nível superior para revisores e mantém as opções de tela centralizadas.
Rotas duplicadas entre grupos - (auth)/index.tsx e (app)/index.tsx ambos mapeiam para /. Correção: Um único hub de redirecionamento app/index.tsx; um grupo é o proprietário de /.
Esquecer parênteses do grupo - auth/login.tsx cria /auth/login, quebrando links de marketing. Correção: Renomeie para (auth)/login.tsx.
Lógica de negócios em _layout.tsx - busca de dados em layouts é executada em cada navegação filho. Correção: Apenas redirecionamento de autenticação; telas são proprietárias dos dados.
Grupo (app) gigante - todas as telas despejadas sob um único grupo. Correção: Subgrupos (tabs), (modals), pastas de funcionalidades.
_components sem underscore - components/Header.tsx se torna a rota /components/Header. Correção: Prefixe pastas privadas com _.
router.push entre grupos com caminho incorreto - chamar /(app)/settings inclui o grupo em algumas APIs. Correção: Use caminhos de URL /settings ou objetos Href tipados.
app/ compartilhado em monorepo - aplicativos white-label divergem nas árvores de rotas. Correção: Separe apps/brand-a/app/ por binário - veja ../project-setup/multiple-apps-in-one-repo/multiple-apps-in-one-repo.md.
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
Grupos de rotas (name) | Organizar sem segmentos de URL | Você precisa de /auth/login na URL pública |
Árvore app/ plana | <10 rotas no total | Esquadrões paralelos editando uma pasta diariamente |
src/routes manual React Navigation | Brownfield sem roteamento baseado em arquivo | Novos aplicativos greenfield SDK 57 |
| Flags de funcionalidades para seções | Abas sazonais | Divisão permanente de autenticação vs aplicativo |
| Aplicativos Expo separados | Produtos verdadeiramente diferentes | Variantes white-label - use configuração em vez disso |
| Espelhamento profundo de pastas do organograma | Nunca recomendado | - |
Não. (auth)/login.tsx mapeia para /login, não /auth/login. Grupos existem puramente para organização de sistema de arquivos e limites de layout.
Sim - app/(app)/(tabs)/(hidden)/ é válido. Cada nome de grupo é removido. Evite aninhamento desnecessário que obscurece o mapa de rotas.
Arquivos e pastas que começam com _ (exceto _layout.tsx) não são transformados em rotas. Use _components/, _hooks/, etc., para código não-rota colocalizado.
Deep links visam caminhos de URL, não nomes de grupos. /settings abre (app)/(tabs)/settings.tsx independentemente das pastas de grupo. Configure scheme em app.config.ts uma vez no nível do aplicativo.
Sim - um app/_layout.tsx monta provedores para ambos os grupos. Separe navegadores por grupo ((auth)/_layout, (app)/_layout), não árvores de provedores duplicadas.
Crie (modals)/ com seu próprio _layout.tsx definindo presentation: "modal". Registre (modals) na pilha raiz. URLs permanecem /compose, não /modals/compose.
Ambos resolveriam para / - um conflito. Use um único app/index.tsx como o redirecionamento de entrada em vez disso.
app/ é a camada de aplicativo do FSD (apenas roteamento). features/, entities/, shared/ vivem fora de app/. Grupos de rotas segmentam fluxos; fatias de funcionalidades segmentam domínios de negócios - veja ../architecture-design/feature-sliced-design-for-rn/feature-sliced-design-for-rn.md.
Quando marketing, SEO (web) ou documentação de suporte publicam o caminho - por exemplo, /pricing para uma página web pública. Use pastas normais, não grupos, quando o segmento deve aparecer na URL.
Mantenha uma tabela docs/routes.md: URL → caminho do arquivo → proprietário da funcionalidade. Atualize a cada novo grupo. Combine com rotas tipadas para que o TypeScript capture desvios.
app/index.tsx(tabs) e (drawer)app/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