Grupos de Rotas
Grupos de rotas usam parênteses (nomeDaPasta) para organizar rotas sem afetar a estrutura da URL. Eles permitem múltiplos layouts no mesmo nível de rota.
Busque em todas as páginas da documentação
Grupos de rotas usam parênteses (nomeDaPasta) para organizar rotas sem afetar a estrutura da URL. Eles permitem múltiplos layouts no mesmo nível de rota.
🤖 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/
├── (marketing)/
│ ├── layout.tsx # Layout de marketing (sem navegação, largura total)
│ ├── page.tsx # / (página inicial)
│ ├── about/page.tsx # /about
│ └── pricing/page.tsx # /pricing
├── (app)/
│ ├── layout.tsx # Layout do aplicativo (barra lateral, autenticação necessária)
│ ├── dashboard/page.tsx # /dashboard
│ └── settings/page.tsx # /settings
└── layout.tsx # Layout raiz (compartilhado por ambos os grupos)
Regra principal: O nome da pasta entre parênteses é removido da URL. (marketing)/about/page.tsx serve /about, não /(marketing)/about.
// app/layout.tsx - Layout raiz compartilhado por todos os grupos
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}// app/(marketing)/layout.tsx - Páginas públicas de marketing
import Link from "next/link";
export default function MarketingLayout({ children }: { children: React.ReactNode }) {
return (
<div>
<header className="flex items-center justify-between px-8 py-4">
<Link href="/" className="text-xl font-bold">Brand</Link>
<nav className="space-x-4">
<Link href="/about">About</Link>
<Link href="/pricing">Pricing</Link>
<Link href="/dashboard">Sign In</Link>
</nav>
</header>
<main>{children}</main>
</div>
);
}// app/(marketing)/page.tsx - Página inicial em /
export default function HomePage() {
return (
<section className="py-20 text-center">
<h1 className="text-5xl font-bold">Welcome to Our Product</h1>
<p className="mt-4 text-lg text-gray-600">The best solution for your needs.</p>
</section>
);
}// app/(app)/layout.tsx - Páginas do aplicativo autenticadas
import { auth } from "@/lib/auth";
import { redirect } from "next/navigation";
import Link from "next/link";
export default async function AppLayout({ children }: { children: React.ReactNode }) {
const session = await auth();
if (!session) redirect("/login");
return (
<div className="flex min-h-screen">
<aside className="w-64 border-r p-4">
<nav className="space-y-2">
<Link href="/dashboard" className="block">Dashboard</Link>
<Link href="/settings" className="block">Settings</Link>
</nav>
</aside>
<main className="flex-1 p-8">{children}</main>
</div>
);
}// app/(app)/dashboard/page.tsx - Dashboard em /dashboard
export default function DashboardPage() {
return <h1>Dashboard</h1>;
}(marketing) nunca aparece na URL - é puramente um mecanismo de organização.app/layout.tsx raiz ainda envolve tudo. Layouts de grupo aninham-se dentro dele.app/layout.tsx de nível superior e colocando um layout.tsx com <html> e <body> dentro de cada grupo. Cada grupo então tem um documento completamente independente.(marketing)/(campaigns)/page.tsx é válido - ambos os segmentos de grupo são removidos.loading.tsx ou error.tsx dentro de um grupo funciona da mesma forma que em qualquer pasta.(marketing)/about/page.tsx E (app)/about/page.tsx - ambos resolvem para /about e o Next.js dará erro.# Múltiplos layouts raiz (documentos HTML completamente separados)
app/
├── (marketing)/
│ ├── layout.tsx # Deve incluir <html> e <body>
│ └── page.tsx # /
├── (app)/
│ ├── layout.tsx # Deve incluir <html> e <body>
│ └── dashboard/
│ └── page.tsx # /dashboard
# Sem app/layout.tsx de nível superior neste padrão
// Usando grupos para separação de autenticação vs. público
// app/(auth)/layout.tsx
export default function AuthLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex min-h-screen items-center justify-center">
<div className="w-full max-w-md">{children}</div>
</div>
);
}
// app/(auth)/login/page.tsx → /login
// app/(auth)/register/page.tsx → /register# Grupos para organização de funcionalidades (sem diferença de layout)
app/
├── (features)/
│ ├── billing/page.tsx # /billing
│ └── invoices/page.tsx # /invoices
├── (admin)/
│ ├── layout.tsx # Layout de administrador com guarda
│ └── users/page.tsx # /users
// Layouts de grupos de rotas têm os mesmos tipos de qualquer layout
interface GroupLayoutProps {
children: React.ReactNode;
}
// Nenhum tipo especial necessário - grupos são puramente um conceito de sistema de arquivos
// Parâmetros de segmentos dinâmicos acima do grupo ainda fluem
// app/(app)/[orgId]/settings/page.tsx
interface SettingsPageProps {
params: Promise<{ orgId: string }>;
}(a)/about/page.tsx e (b)/about/page.tsx existirem, a compilação falha./ só pode existir em um grupo. Coloque page.tsx no grupo que deve possuir a URL raiz.<html>, navegar entre grupos aciona um recarregamento completo da página.(a)/(b)/page.tsx é permitido, mas ambas as camadas são removidas - a URL é apenas /.loading.tsx e error.tsx em um grupo se aplicam a todas as rotas dentro desse grupo - eles não vazam para outros grupos.| Abordagem | Quando Usar |
|---|---|
| Pastas aninhadas sem parênteses | Quando a pasta deve aparecer na URL |
Rotas Paralelas (@slot) | Renderizando múltiplas visualizações simultaneamente em um layout |
| Redirecionamentos baseados em middleware | Roteando usuários para diferentes seções com base em autenticação ou função |
| Aplicativos Next.js separados | Implantações completamente independentes para diferentes seções |
Não. O nome entre parênteses é completamente removido. (marketing)/about/page.tsx serve /about, não /(marketing)/about.
Não. Se (a)/about/page.tsx e (b)/about/page.tsx existirem, a compilação falha porque ambos resolvem para /about.
Apenas um grupo pode conter page.tsx em sua raiz. Coloque-o no grupo que deve possuir a URL / (geralmente o grupo de marketing ou público).
Ocorre um recarregamento completo da página. Quando cada grupo tem seu próprio <html> e <body> (múltiplos layouts raiz), a navegação entre grupos não pode ser uma transição suave do lado do cliente.
Não. Eles se aplicam apenas às rotas dentro desse grupo. Os arquivos de limite de cada grupo são limitados às suas próprias rotas.
Não. Matchers de middleware funcionam em caminhos de URL reais. Os nomes das pastas entre parênteses são invisíveis para o middleware. Corresponda à URL real como /about, não /(marketing)/about.
Remova o app/layout.tsx de nível superior e coloque um layout.tsx com <html> e <body> dentro de cada grupo.
app/
├── (marketing)/
│ ├── layout.tsx # Deve incluir <html> e <body>
│ └── page.tsx
├── (app)/
│ ├── layout.tsx # Deve incluir <html> e <body>
│ └── dashboard/page.tsx
Sim. (a)/(b)/page.tsx é válido. Ambos os segmentos de grupo são removidos, então a URL é apenas /.
Os mesmos tipos de qualquer layout. Não há tipos especiais para grupos de rotas, pois são puramente um conceito de sistema de arquivos.
interface GroupLayoutProps {
children: React.ReactNode;
}// app/(app)/[orgId]/settings/page.tsx
interface SettingsPageProps {
params: Promise<{ orgId: string }>;
}Parâmetros de segmentos dinâmicos acima do grupo ainda fluem normalmente.
Verifique a autenticação no layout do grupo e redirecione se não estiver autenticado.
// app/(app)/layout.tsx
import { auth } from "@/lib/auth";
import { redirect } from "next/navigation";
export default async function AppLayout({
children,
}: { children: React.ReactNode }) {
const session = await auth();
if (!session) redirect("/login");
return <div>{children}</div>;
}Sim. Eles podem ser usados puramente para organização do sistema de arquivos, agrupando rotas relacionadas sem afetar a estrutura da URL.
Revisado por Chris St. John·Última atualização: 10 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥