Next.js Route Groups — Organize Routes Without Affecting URLs
Advertisement
Introduction
Route groups in Next.js let you organize your app directory into logical sections without adding those folder names to the URL. A folder named (marketing) groups marketing pages together — but routes inside it still render at their direct path, not at /marketing/. This simple convention unlocks some of the most powerful architectural patterns in the App Router.
Why This Matters
Without route groups, every folder in your app directory becomes a URL segment. If you want a different layout for authenticated pages vs public pages, you have two options: a single layout with conditional logic (messy), or nested URL paths like /app/dashboard (ugly).
Route groups solve this elegantly. (auth) and (public) can coexist at the root with completely different layouts, and neither folder name appears in any URL. Your routes stay clean, your architecture stays organized, and your layouts stay separated.
Basic Syntax
Wrap a folder name in parentheses to make it a route group:
app/
├── (marketing)/
│ ├── layout.tsx ← marketing layout
│ ├── page.tsx → /
│ ├── about/
│ │ └── page.tsx → /about
│ └── blog/
│ └── page.tsx → /blog
├── (auth)/
│ ├── layout.tsx ← auth layout
│ ├── login/
│ │ └── page.tsx → /login
│ └── register/
│ └── page.tsx → /register
└── (dashboard)/
├── layout.tsx ← dashboard layout
└── dashboard/
└── page.tsx → /dashboardURLs: /, /about, /blog, /login, /register, /dashboard — no group names appear anywhere.
Separate Layouts per Section
The most common use case: apply different layouts to different sections without URL nesting:
// app/(marketing)/layout.tsx
export default function MarketingLayout({ children }: { children: React.ReactNode }) {
return (
<div>
<header className="bg-white border-b">
<nav className="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between">
<a href="/" className="text-xl font-bold">MyApp</a>
<div className="flex gap-6">
<a href="/about">About</a>
<a href="/blog">Blog</a>
<a href="/login" className="bg-black text-white px-4 py-2 rounded">Sign in</a>
</div>
</nav>
</header>
<main>{children}</main>
<footer className="bg-gray-50 border-t py-12 text-center text-gray-500">
© 2026 MyApp
</footer>
</div>
)
}// app/(dashboard)/layout.tsx
import { auth } from '@/lib/auth'
import { redirect } from 'next/navigation'
import { Sidebar } from '@/components/Sidebar'
export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
const session = await auth()
if (!session) redirect('/login')
return (
<div className="flex h-screen bg-gray-100">
<Sidebar user={session.user} />
<div className="flex-1 overflow-auto">
<main className="p-8">{children}</main>
</div>
</div>
)
}// app/(auth)/layout.tsx
export default function AuthLayout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="w-full max-w-md bg-white rounded-xl shadow-lg p-8">
{children}
</div>
</div>
)
}Multiple Root Layouts
Route groups enable multiple root-level layouts — each can define its own html and body tags:
app/
├── (marketing)/
│ └── layout.tsx ← html + body, light theme
└── (app)/
└── layout.tsx ← html + body, dark theme, different fontsThis is only possible when there is NO app/layout.tsx at the top level.
Co-locating Related Files
Route groups also work for file organization without layout separation. Group related pages and their components together:
app/
├── (checkout)/
│ ├── cart/
│ │ ├── page.tsx → /cart
│ │ └── CartItem.tsx ← co-located component
│ ├── checkout/
│ │ ├── page.tsx → /checkout
│ │ └── CheckoutForm.tsx ← co-located component
│ └── order-confirmation/
│ └── page.tsx → /order-confirmation
└── (products)/
├── products/
│ └── page.tsx → /products
└── products/
└── [id]/
├── page.tsx → /products/[id]
└── ProductGallery.tsxPreventing URL Collisions
Route groups at the same level can have pages that resolve to the same URL if you are not careful. Two route groups cannot both define a page.tsx for the same URL:
app/
├── (marketing)/
│ └── page.tsx → / ✓
└── (app)/
└── page.tsx → / ✗ CONFLICT — two pages for /Only one group should define a page.tsx for each URL.
Organizing API Routes
Group API routes logically without affecting endpoint URLs:
app/
├── api/
│ ├── (auth)/
│ │ ├── login/
│ │ │ └── route.ts → /api/login
│ │ └── register/
│ │ └── route.ts → /api/register
│ ├── (posts)/
│ │ ├── route.ts → /api/posts (GET all, POST new)
│ │ └── [id]/
│ │ └── route.ts → /api/posts/[id]
│ └── (users)/
│ └── [id]/
│ └── route.ts → /api/users/[id]Combining Route Groups with Parallel Routes
Route groups and parallel routes work together for complex dashboard layouts:
app/
└── (dashboard)/
├── layout.tsx ← dashboard shell with @analytics slot
├── page.tsx → /
├── @analytics/
│ └── page.tsx ← analytics panel slot
└── settings/
└── page.tsx → /settingsCommon Mistakes
- Expecting the route group name to appear in the URL — it never does, by design
- Creating the same URL in multiple route groups (e.g., two
page.tsxfiles that resolve to/) - Forgetting that route group layouts still need
htmlandbodytags if they are root layouts - Using route groups purely for visual organization when a simple flat structure would be clearer
- Nesting route groups unnecessarily —
(admin)/(users)/page.tsxresolves to/not/admin/users
Best Practices
- Use route groups to separate concerns:
(marketing),(auth),(dashboard),(api) - Apply auth checks in the dashboard layout — route groups make this clean and non-repetitive
- Use groups for co-location: keep page components, types, and utilities close to their pages
- Document your route group conventions in a brief comment in
app/layout.tsxor aREADME - Combine with parallel routes
@slotNamefor complex dashboard panel layouts
Key Takeaways
- Route groups use
(name)folder syntax — the name never appears in the URL - They enable multiple distinct layouts at the same URL level (e.g., auth vs dashboard vs marketing)
- Multiple root-level layouts using route groups require no top-level
app/layout.tsx - Route groups can organize files without changing routing behavior — useful for co-location
- Two route groups cannot define
page.tsxfor the same URL path — this causes a build error - Auth checks placed in a group layout protect all pages in the group without per-page repetition
- Route groups work with
(.)intercepting routes,@slotparallel routes, and[dynamic]segments - There is no performance cost to route groups — they are a build-time organizational convention only
Advertisement