React
Route groups and nested layouts in the App Router
Folders in parentheses add no URL segment. They split layouts, and nested layouts stay mounted as you navigate. Rules and the traps.
Key points
- A folder in parentheses is a route group: it does not appear in the URL.
- Each group can carry its own root layout, with html and body.
- A nested layout does not re-render when you navigate beneath it.
- Two pages that resolve to the same URL stop the build.
A route group is a folder in parentheses that adds no URL segment: it gives two parts of the site different layouts and boundaries. A nested layout, by contrast, stays mounted as you navigate and does not re-render.
The structure
app/
layout.tsx # root: html, body, font
(marketing)/
layout.tsx # public header
page.tsx # /
pricing/page.tsx # /pricing
(app)/
layout.tsx # shell with sidebar
dashboard/
layout.tsx # section title and tabs
page.tsx # /dashboard
settings/page.tsx # /dashboard/settings
(auth)/
layout.tsx
login/page.tsx # /login
None of the three parenthesised folders appears in the URL: /pricing, /dashboard/settings and /login are the real addresses. The group only decides which layout wraps the page.
What a nested layout does
A layout receives children and stays mounted while navigation remains inside its segment. Moving from /dashboard to /dashboard/settings re-renders the page, not the shell: sidebar state survives.
// app/(app)/dashboard/layout.tsx
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
Dashboard
{children}
);
}
The layout does not receive searchParams: only the page gets them. If a filter lives in the URL and the shell needs it too, read the parameter in the page and pass it as a prop to a client component.
When the group earns its place
| Case | Groups | Why |
|---|---|---|
| Marketing site and product | (marketing) and (app) | Different header and navigation, one domain |
| Two root layouts | (shop) and (docs) | Each with its own html and body; moving between them reloads the page |
| Login and password reset | (auth) | Outside the shell, no sidebar |
The mistakes you pay for
- Two
page.tsxfiles that resolve to the same URL: the build fails with a path conflict. - A layout that reads
searchParams: it never receives them. - Session logic in the root layout: it costs a query on every request, even for pages that do not need it.
- Groups created to group files: if the layouts are identical, the group does nothing.
Layouts are built from blocks, not whole pages: header, sidebar and footer land in your repository and follow your tree.
The general picture is in how to structure an App Router project; for parallel panels there is parallel routes and for waiting streaming and Suspense. The framework comparison is Astro vs Next.js.
npx next build
Known limitation: a route group changes neither the URL nor the file path. If two groups declare the same route, Next.js does not pick one: it stops the build.
Frequently asked questions
Does a route group change the URL?
No. The parentheses drop the folder from the path: pricing inside (marketing) stays /pricing.
Can I have two root layouts?
Yes, if each group has its own layout with html and body. Moving between groups reloads the whole page, so you lose client navigation.
Does the layout re-render on every navigation?
No, while you stay inside its segment. It changes when navigation leaves the layout, or when the shared data is invalidated on the server.
Where do I put the session check?
In the page, or in a server component the page calls. In the layout it costs a query even for routes that do not use it.
Do route groups work with parallel routes?
Yes, a slot can sit inside a group. The group picks the layout, the slot picks the panel: two different axes.