Route Groups let you organize your Next.js App Router file structure into logical sections without those sections appearing in the URL. A route at app/(marketing)/about/page.tsx serves at /about — the (marketing) group is invisible to the browser. This matters a lot when you need different layouts for different parts of your app without creating URL segments for the layout difference.
Here's the complete pattern, including nested groups, group-specific layouts, and the use cases that actually benefit from this approach — including the content organization used at content organization approach.
The Basics
Create a route group by wrapping a folder name in parentheses:
app/
├── (marketing)/ ← Route group — doesn't appear in URL
│ ├── layout.tsx ← Layout for marketing pages only
│ ├── about/
│ │ └── page.tsx ← Serves at /about
│ ├── pricing/
│ │ └── page.tsx ← Serves at /pricing
│ └── blog/
│ └── page.tsx ← Serves at /blog
├── (dashboard)/ ← Different route group
│ ├── layout.tsx ← Different layout for dashboard
│ ├── overview/
│ │ └── page.tsx ← Serves at /overview
│ └── settings/
│ └── page.tsx ← Serves at /settings
└── layout.tsx ← Root layout (applies to everything)
The marketing group has a layout with a public header and footer. The dashboard group has a layout with a sidebar and authenticated navigation. Both serve routes at the same URL level without the group name appearing anywhere.
Group-Specific Layouts
The main reason to use route groups: different layouts for different sections of the app without creating extra URL nesting.
// app/(marketing)/layout.tsx
export default function MarketingLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<>
<PublicHeader />
<main className="max-w-7xl mx-auto px-4">{children}</main>
<PublicFooter />
</>
);
}
// app/(dashboard)/layout.tsx
import { redirect } from 'next/navigation';
import { getSession } from '@/lib/auth';
export default async function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
const session = await getSession();
if (!session) redirect('/login');
return (
<div className="flex h-screen">
<DashboardSidebar />
<main className="flex-1 overflow-auto p-6">{children}</main>
</div>
);
}
The auth check in the dashboard layout applies to every route in the group — cleaner than adding it to each individual page.
Opting Out of a Layout
If you have a route that doesn't belong in any group, or needs its own layout, place it outside the groups:
app/
├── (marketing)/
│ └── ...
├── (dashboard)/
│ └── ...
├── login/ ← No group — uses only root layout
│ └── page.tsx ← Serves at /login, no public header or dashboard sidebar
└── layout.tsx ← Root layout only
The login page uses only the root layout. Neither the marketing header/footer nor the dashboard sidebar applies to it.
Multiple Root Layouts
Route groups can each have their own separate root layout — including their own <html> and <body> tags. This is used when different parts of an app are so different they need completely separate HTML structures:
app/
├── (app)/
│ ├── layout.tsx ← Has <html>, <body>, loads app fonts/styles
│ └── dashboard/
│ └── page.tsx
├── (marketing)/
│ ├── layout.tsx ← Has <html>, <body>, loads marketing fonts/styles
│ └── home/
│ └── page.tsx
When using multiple root layouts, each group's layout must include <html> and <body> tags, and there should be no root app/layout.tsx. This is a more advanced pattern — typically used when an app and its marketing site share a codebase but have genuinely different visual identities.
Shared Layouts Across Groups
Sometimes pages from different groups need the same layout component without being in the same group. A few options:
Create a shared component and import it in both group layouts:
// components/SiteHeader.tsx
export function SiteHeader() {
return <header>...</header>;
}
// app/(marketing)/layout.tsx
import { SiteHeader } from '@/components/SiteHeader';
// app/(dashboard)/layout.tsx
// Also import SiteHeader if it should appear here too
Use a parent layout — the root layout applies to all routes regardless of group:
// app/layout.tsx — applies everywhere
export default function RootLayout({ children }) {
return (
<html>
<body>
<SiteHeader /> {/* Appears on all pages */}
{children}
</body>
</html>
);
}
Common Use Cases
Marketing vs. App: Separate layouts for a public marketing site and the authenticated app within the same Next.js project.
Admin vs. User: Different navigation and permissions for admin users versus regular users.
Multi-tenant apps: Different brand layouts for different tenant segments sharing the same codebase.
A/B testing layouts: Two groups with the same routes but different layout implementations, controlled by a middleware that rewrites to one group or the other.
Organizing large projects: Even without different layouts, groups help organize large projects into logical sections. The URL structure stays clean while the file structure communicates meaning.
What Route Groups Are Not
Route groups don't create URL segments — that's the whole point. If you want a URL like /dashboard/overview, you need the dashboard folder in your file structure normally, not as a group. Groups are for layout organization and code organization, not for URL structuring.
Debugging Route Group Issues
Layout not applying: Check that the route file is inside the group folder, not just that the group folder exists. A page at app/(marketing)/page.tsx uses the marketing layout. A page at app/page.tsx doesn't.
Unexpected 404: Route groups can't have conflicting routes. If app/(a)/about/page.tsx and app/(b)/about/page.tsx both exist, Next.js will error — two routes resolving to /about is a conflict regardless of which groups they're in.
Layout inheritance confusion: The root layout always applies. Group layouts apply additionally for routes inside the group. There's no way to "opt out" of the root layout for a specific group — if you need that, use multiple root layouts as described above.
Navigating between groups: Client-side navigation between routes in different groups works normally. The user navigating from /about (in the marketing group) to /dashboard (in the dashboard group) triggers a full layout swap — the marketing layout unmounts and the dashboard layout mounts. This is expected behavior.
Summary
Route groups (parentheses-wrapped folders) organize your app's file structure without affecting URLs. Their primary use is applying different layouts to different sections of an app — a marketing layout for public pages, a dashboard layout for authenticated pages — without the section name appearing in the URL. Secondary use: organizing large projects into logical code groups even when the layout difference doesn't apply.
TypeScript Types for Route Group Layouts
When writing group layouts with TypeScript, the props type is consistent across all layouts:
// Works for any group layout
type LayoutProps = {
children: React.ReactNode;
};
// With parallel routes in a group
type GroupLayoutWithParallelProps = {
children: React.ReactNode;
modal: React.ReactNode; // @modal parallel route
sidebar: React.ReactNode; // @sidebar parallel route
};
// With params when the group contains dynamic routes
type DynamicGroupLayoutProps = {
children: React.ReactNode;
params: {
// If the GROUP contains a dynamic segment
// e.g. app/(dashboard)/[orgId]/settings/
orgId: string;
};
};
The group itself never contributes a param — only actual named segments in square brackets do. Route groups are invisible to TypeScript params just as they're invisible to URLs.
When Not to Use Route Groups
Route groups add a layer of indirection that makes the file system harder to navigate for new contributors. If you're not getting a layout benefit from the group — if all routes in the group use the same layout as adjacent routes — the group is adding complexity without adding value.
Use route groups when: you need different layouts for different sections, you're organizing a large project into logical units, or you're implementing multiple root layouts.
Skip route groups when: you're using them purely to add nested folders for aesthetic reasons, all routes use the same layout anyway, or the project is small enough that the organization overhead costs more than it saves.