Skip to main content

Групи маршрутів у Next.js

Групи маршрутів (route groups) у Next.js — папки в дужках, які структурують проект без будь-якого впливу на URL-шлях.

Теорія

TL;DR

  • Синтаксис: назва папки в дужках, наприклад (marketing) або (auth)
  • Назва папки ніколи не з'являється в URL
  • Кожна група може мати власний layout.tsx, loading.tsx і error.tsx
  • Головне застосування: різні лейаути для публічних і авторизованих сторінок
  • Якщо дві групи дають однаковий URL — Next.js видасть помилку під час білду

Короткий приклад

app/ (marketing)/ about/page.tsx → /about pricing/page.tsx → /pricing (dashboard)/ settings/page.tsx → /settings analytics/page.tsx → /analytics

Папки (marketing) і (dashboard) роутер повністю ігнорує. URL-адреси: /about, /pricing, /settings, /analytics. Назви груп зникають.

Чим групи відрізняються від звичайних папок

Звичайна папка app/marketing/about/page.tsx дає URL /marketing/about. Папка з групою app/(marketing)/about/page.tsx дає просто /about. Одна відмінність, але з конкретним наслідком: до кожної групи можна прикріпити окремий layout.tsx. Тоді /about і /pricing матимуть лейаут з публічним navbar і footer, а /settings і /analytics — лейаут із sidebar і перевіркою авторизації. Жодного зайвого сегмента в URL.

Як роутер обробляє назви груп

Next.js читає дужки як сигнал виключити папку з генерації URL. Папка все одно існує на диску і може містити будь-які спеціальні файли: layout.tsx, loading.tsx, error.tsx, template.tsx. Роутер сприймає групу як область видимості, а не як сегмент шляху.

Коли використовувати

  • Публічний сайт і особистий кабінет з різними лейаутами
  • Сторінки авторизації (/login, /register, /forgot) під спільним wrapper-ом
  • Адмінка з окремим кореневим лейаутом і власними тегами <html> та <body>
  • Велика кодова база, організована за функціями, без забруднення URL

Типові помилки

Конфліктні шляхи в різних групах:

// Обидва дають /about — Next.js видасть помилку під час білду app/(marketing)/about/page.tsx app/(info)/about/page.tsx

Дужки ховають назву папки від URL, але не від логіки роутингу. Я бачив, як цей конфлікт спливає на код-рев'ю, коли два розробники в один день додають сторінки до різних груп. Варто тримати плоский список усіх URL-шляхів при плануванні структури.

Помилкове відчуття захисту від конфліктів:

// Назви груп різні, але маршрути все одно конфліктують app/(site)/contact/page.tsx → /contact app/(support)/contact/page.tsx → /contact ❌

Обидва шляхи ведуть до /contact. Назва групи не має значення для кінцевого URL.

Сторінки поза групами при кількох кореневих лейаутах:

Якщо розбити додаток на (main) і (admin) з окремими кореневими лейаутами і видалити app/layout.tsx, кожен маршрут верхнього рівня має бути всередині однієї з груп. Сторінка app/about/page.tsx поза групами не матиме кореневого лейаута.

Запитання на співбесіді

Q: Чи можна вкладати групи маршрутів одна в одну?
A: Так. app/(marketing)/(campaigns)/summer/page.tsx — валідний шлях, і жодна назва групи не з'являється в URL. Більшість команд вдається до вкладеності тільки коли підсекції потрібен власний спільний лейаут.

Q: Як групи маршрутів впливають на middleware?
A: Ніяк. Middleware зіставляє реальний URL-шлях, а не структуру файлів. Матчер /dashboard/:path* працює однаково незалежно від того, лежать файли в app/dashboard/ чи в app/(auth)/dashboard/.

Q: Яка різниця між лейаутом групи і звичайним вкладеним лейаутом?
A: Звичайний вкладений лейаут додає сегмент до URL. Лейаут групи обгортає маршрути так само, але без додавання сегмента. Поведінка обгортання ідентична.

Q: Якщо дві групи-сусіди мають layout.tsx, вони накладаються?
A: Вони обидві накладаються на кореневий app/layout.tsx, але між собою не взаємодіють. Кожен маршрут належить рівно одній групі.

Приклади

Окремі лейаути для публічної частини і дашборду

Маркетинговий сайт і дашборд живуть в одному Next.js-проекті, але потребують різного оформлення сторінок. Групи маршрутів вирішують це без зміни URL.

tsx
// app/(marketing)/layout.tsx export default function MarketingLayout({ children, }: { children: React.ReactNode; }) { return ( <div> <PublicNavbar /> <main>{children}</main> <Footer /> </div> ); } // app/(dashboard)/layout.tsx export default function DashboardLayout({ children, }: { children: React.ReactNode; }) { return ( <div className="flex"> <Sidebar /> <main className="flex-1">{children}</main> </div> ); }

/about і /pricing отримують navbar і footer. /settings і /analytics — sidebar. Жодна назва групи не потрапляє в URL.

Кілька кореневих лейаутів

Коли адмінці потрібна інша структура <html>, інші шрифти або суворіші правила CSP, можна видалити app/layout.tsx і дати кожній групі власний кореневий лейаут.

app/ (main)/ layout.tsx ← кореневий лейаут з аналітикою і open graph тегами page.tsx about/page.tsx (admin)/ layout.tsx ← спрощений кореневий лейаут без сторонніх скриптів dashboard/page.tsx users/page.tsx

Кожен layout.tsx тут — повноцінний HTML-документ з <html>, <head> і <body>. Next.js рендерить кожну секцію зі своєю оболонкою. Якщо обрати цей підхід, кожна сторінка має лежати всередині однієї з груп — запасного варіанту немає.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?