Next.js Route Groups — Organize Routes Without Affecting URLs

Sanjeev SharmaSanjeev Sharma
6 min read

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  → /dashboard

URLs: /, /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 fonts

This is only possible when there is NO app/layout.tsx at the top level.

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.tsx

Preventing 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        → /settings

Common 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.tsx files that resolve to /)
  • Forgetting that route group layouts still need html and body tags 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.tsx resolves 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.tsx or a README
  • Combine with parallel routes @slotName for 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.tsx for 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, @slot parallel routes, and [dynamic] segments
  • There is no performance cost to route groups — they are a build-time organizational convention only

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro