Noções Básicas do App Router
O App Router usa um roteador baseado em sistema de arquivos onde pastas definem rotas e arquivos especiais definem UI e comportamento.
Busque em todas as páginas da documentação
O App Router usa um roteador baseado em sistema de arquivos onde pastas definem rotas e arquivos especiais definem UI e comportamento.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida - pronto para copiar e colar.
app/
├── layout.tsx # Layout raiz (obrigatório)
├── page.tsx # Rota inicial → /
├── loading.tsx # UI de carregamento para /
├── error.tsx # Limite de erro para /
├── not-found.tsx # UI 404 para /
├── about/
│ └── page.tsx # /about
├── blog/
│ ├── layout.tsx # Layout aninhado para /blog/*
│ ├── page.tsx # /blog
│ └── [slug]/
│ └── page.tsx # /blog/:slug
└── api/
└── health/
└── route.tsx # GET /api/health
Regra principal: Uma rota só é publicamente acessível quando uma pasta contém um arquivo page.tsx ou route.tsx.
// app/layout.tsx - Layout Raiz (obrigatório, envolve todas as páginas)
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Meu App",
description: "Construído com o App Router do Next.js",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}// app/page.tsx - Página inicial (Componente de Servidor por padrão)
export default function HomePage() {
return (
<main>
<h1>Bem-vindo</h1>
<p>Este é um Componente de Servidor - nenhum JS do lado do cliente foi enviado.</p>
</main>
);
}// app/dashboard/page.tsx - Rota aninhada em /dashboard
export default function DashboardPage() {
return <h1>Dashboard</h1>;
}// app/api/health/route.tsx - Route Handler (endpoint de API)
import { NextResponse } from "next/server";
export async function GET() {
return NextResponse.json({ status: "ok", timestamp: Date.now() });
}Quando usar isso: Todo projeto Next.js 15+ usa o App Router. Comece aqui ao criar qualquer nova rota, layout ou endpoint de API.
app/ mapeia para um segmento de URL. app/blog/settings/page.tsx serve /blog/settings.page.tsx, layout.tsx, loading.tsx, error.tsx, not-found.tsx, route.tsx, template.tsx e default.tsx."use client" no topo.route.tsx e page.tsx não podem coexistir na mesma pasta. Um segmento de rota é uma página ou uma rota de API, não ambos.loading.tsx cria um limite <Suspense> automático. O Next.js envolve a página em Suspense usando loading.tsx como fallback.error.tsx cria um Limite de Erro automático. Ele captura erros na página e seus filhos, mas não no layout no mesmo nível.// app/template.tsx - Semelhante ao layout, mas é remontado em cada navegação
export default function Template({ children }: { children: React.ReactNode }) {
return <div className="animate-fade-in">{children}</div>;
}// app/not-found.tsx - Página 404 global
export default function NotFound() {
return (
<div>
<h2>404 - Página Não Encontrada</h2>
<p>A página que você procura não existe.</p>
</div>
);
}// app/api/users/route.tsx - Route handler com múltiplos métodos
import { NextRequest, NextResponse } from "next/server";
export async function GET() {
const users = await db.user.findMany();
return NextResponse.json(users);
}
export async function POST(request: NextRequest) {
const body = await request.json();
const user = await db.user.create({ data: body });
return NextResponse.json(user, { status: 201 });
}// O Next.js fornece tipos integrados para props de página e layout
// As props de página no Next.js 15+ usam params baseados em Promise
interface PageProps {
params: Promise<{ slug: string }>;
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
}
// As props de layout sempre incluem children
interface LayoutProps {
children: React.ReactNode;
params: Promise<{ slug: string }>;
}layout.tsx não é re-renderizado na navegação. Se você precisar de estado atualizado a cada navegação, use template.tsx em vez disso.error.tsx não captura erros no layout do mesmo nível. Para capturar erros de layout, coloque error.tsx no segmento pai.route.tsx deve exportar métodos HTTP nomeados (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS). Exports padrão são ignorados.await params dentro de páginas e layouts - a API síncrona foi depreciada.searchParams também são assíncronos no Next.js 15+. Use await searchParams ou use(searchParams) - não desestruture de forma síncrona.not-found.tsx na raiz captura todas as rotas não correspondentes. not-found.tsx em nível de segmento só é acionado quando você chama notFound().| Abordagem | Quando Usar |
|---|---|
Pages Router (pages/ dir) | Projetos legados ainda não migrados |
Handler route.tsx | Endpoints apenas de API sem UI |
template.tsx | Necessidade de nova instância de componente em cada navegação |
| Roteador de terceiros (TanStack Router) | Aplicativos React não-Next.js que precisam de roteamento type-safe |
Uma rota só é publicamente acessível quando uma pasta contém um arquivo page.tsx ou route.tsx. Outros arquivos (componentes, utilitários, estilos) colocados na pasta não são expostos como rotas.
Não. Um segmento de rota é uma página ou uma rota de API, nunca ambos. Coloque seu route.tsx em uma pasta separada (por exemplo, app/api/health/route.tsx).
Server Components por padrão. Você deve adicionar "use client" no topo de um arquivo para torná-lo um Client Component.
layout.tsx persiste entre navegações e não é remontadotemplate.tsx é remontado a cada navegação, fornecendo estado novo a cada veztemplate.tsx para animações de entrada/saída ou logging por navegaçãoO limite de erro criado por error.tsx envolve a página, não o layout irmão. Para capturar erros de layout, coloque error.tsx no segmento pai.
O Next.js envolve automaticamente a página em <Suspense fallback={<Loading />}>. A UI de carregamento aparece instantaneamente enquanto a página é transmitida.
Quebra. Tanto params quanto searchParams agora são objetos Promise no Next.js 15+. Você deve await params dentro de páginas e layouts. A API síncrona foi depreciada.
// app/api/users/route.tsx
import { NextRequest, NextResponse } from "next/server";
export async function GET() {
return NextResponse.json({ users: [] });
}
export async function POST(request: NextRequest) {
const body = await request.json();
return NextResponse.json(body, { status: 201 });
}not-found.tsx raiz captura todas as rotas não correspondentes automaticamentenot-found.tsx em nível de segmento só é acionado quando você chama notFound() de next/navigationinterface PageProps {
params: Promise<{ slug: string }>;
searchParams: Promise<{
[key: string]: string | string[] | undefined;
}>;
}
interface LayoutProps {
children: React.ReactNode;
params: Promise<{ slug: string }>;
}import { NextRequest, NextResponse } from "next/server";
export async function GET(): Promise<NextResponse> {
return NextResponse.json({ status: "ok" });
}
export async function POST(
request: NextRequest
): Promise<NextResponse> {
const body = await request.json();
return NextResponse.json(body, { status: 201 });
}Ele é ignorado. route.tsx deve exportar métodos HTTP nomeados (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS). Exports padrão não fazem nada.
Sim. Arquivos não especiais (componentes, utilitários, estilos, testes) colocados dentro de pastas de rota não são expostos como rotas. Apenas arquivos com nomes reservados como page.tsx e route.tsx são tratados como rotas.
Revisado por Chris St. John·Última atualização: 10 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥