В файловой маршрутизации App Router физическая структура папок напрямую транслируется в общедоступный URL. Однако в архитектуре масштабных enterprise-приложений требования к организации исходного кода часто конфликтуют с требованиями к публичной структуре адресов:
/login и полноразмерная рабочая среда /dashboard).Next.js App Router решает эту задачу с помощью концепции Route Groups (групп маршрутов). Оборачивание имени папки в круглые скобки указывает сборщику Turbopack, что данный сегмент файловой системы предназначен исключительно для организации модулей и применения макетов, и полностью исключается из итогового пути URL.
Когда компилятор Next.js обходит директорию app, имена папок, заключенные в круглые скобки (folderName), служат разделителями на уровне файловой системы, но удаляются из строки адреса при построении таблицы маршрутов:
app/(marketing)/about/page.tsx компилируется в URL /about.app/(dashboard)/analytics/page.tsx компилируется в URL /analytics.app/(shop)/checkout/page.tsx компилируется в URL /checkout.При этом компилятор сохраняет группу во внутреннем Route Segment Tree ID. Это позволяет назначать группе собственный независимый layout.tsx, loading.tsx и error.tsx.
Turbopack сканирует файловую структуру app/ и обнаруживает папки в круглых скобках (marketing), (dashboard).
Имена групп вырезаются из таблицы URL: путь app/(marketing)/pricing/page.tsx регистрируется как публичный /pricing.
Страница связывается с макетом своей группы: pricing/page.tsx оборачивается в (marketing)/layout.tsx.
При переходе проверяется общий предок: если обе страницы внутри одного Root Layout — переход мягкий (SPA), иначе — hard reload.
Сервер генерирует Flight stream с разметкой страницы и макета целевой группы без лишних зависимостей.
В проекте создан файл app/(auth)/admin/login/page.tsx. По какому общедоступному URL будет открываться эта страница в браузере?
В рамках единого приложения разные разделы могут требовать разную компоновку. Создавая группы, вы изолируете макеты без изменения структуры URL:
app/
├── (marketing)/
│ ├── layout.tsx # Публичный каркас (Хедер, Промо-баннер, Футер)
│ ├── page.tsx # URL: / (Главный лендинг)
│ ├── about/page.tsx # URL: /about
│ └── pricing/page.tsx # URL: /pricing
└── (dashboard)/
├── layout.tsx # Приватный каркас (Сайдбар с проектами, меню профиля)
├── dashboard/page.tsx # URL: /dashboard
└── settings/page.tsx # URL: /settingsNext.js позволяет полностью удалить корневой app/layout.tsx и создать независимые Root Layouts внутри каждой группы:
export default function MarketingRootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ru">
<body className="marketing-theme">
{/* Чистый статический HTML без тяжелых клиентских провайдеров */}
<header className="marketing-header">Маркетинг</header>
{children}
</body>
</html>
);
}import { AuthProvider } from '@/components/auth/AuthProvider';
export default function AppRootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ru">
<body className="app-theme">
{/* Здесь подключены тяжелые клиентские провайдеры сессии */}
<AuthProvider>
{children}
</AuthProvider>
</body>
</html>
);
}Что произойдет в браузере, когда пользователь перейдет по ссылке с маркетинговой страницы /pricing (app/(marketing)/layout.tsx) на страницу приложения /dashboard (app/(app)/layout.tsx)?
В коммерческих проектах критично, чтобы лендинг загружался мгновенно с наивысшим показателем Core Web Vitals (LCP менее 1.2 с). Использование Route Groups позволяет изолировать клиентские провайдеры авторизации и вебсокетов исключительно в группе (app), сохраняя (marketing) полностью легковесной:
app/
├── layout.tsx (Общий Root Shell)
├── (marketing)/
│ ├── layout.tsx ──► Zero JS-Bundle: чистый SSR/SSG
│ └── page.tsx ──► LCP: 0.6 сек (CDN Edge Cache)
└── (workspace)/
├── layout.tsx ──► Содержит AuthContext, WebSocketProvider, ReactQuery
└── editor/page.tsx ──► Интерактивная рабочая средаПоскольку имена папок в круглых скобках исключаются из URL, создание одинаковых относительных путей в разных группах приведет к ошибке сборки Turbopack:
app/(marketing)/about/page.tsx $\to$ /aboutapp/(shop)/about/page.tsx $\to$ /about
Как избежать: Следите за уникальностью результирующих путей и используйте плагины линтинга структуры папок (например, eslint-plugin-check-file).Если проект разбит на несколько корневых макетов, переход между ними вызывает полную перезагрузку страницы (window.location). В результате любые несохраненные данные форм в оперативной памяти будут потеряны.
Как избежать: Используйте единый app/layout.tsx для всего приложения в 95% случаев, а группы маршрутов применяйте для вложенных макетов.