Routing and Layouts
How the app/ directory is structured, what route groups are, and how layouts nest.
The app/ boundary
app/ holds only Next.js file-convention files - page.tsx, layout.tsx,
error.tsx, not-found.tsx, loading.tsx, route.ts. These are reserved
filenames the router discovers by location, so they must live here.
Route groups
Parentheses folders - (name)/ - are Next.js route groups. The name is
invisible to the URL: app/(app)/dashboard/page.tsx is still /dashboard.
Their only purpose is layout segmentation - grouping pages that share a
common layout without that grouping appearing in the URL.
This template ships with two route groups plus a restricted catch-all:
The route groups and their purpose at a glance:
| Location | What lives here | Rule |
|---|---|---|
app/ | Next.js file-convention files only | page.tsx, layout.tsx, error.tsx, not-found.tsx etc. - thin shells that delegate to components/ and classes/. No business logic. |
app/(app)/ | Authenticated app pages | All pages that require a signed-in user. Layout mounts the auth gate and navbar automatically. |
app/(auth)/ | Auth pages | Sign-in and sign-up. Bare layout - no navbar, no auth gate. |
app/restricted/ | Role-based access denial | Shown when a signed-in user lacks a qualifying role (Admin or SuperAdmin) for app access. Lives outside (app)/ so it can be reached without passing the role check again. |
Layout nesting
Layouts nest from the outside in. Every request passes through all layouts from the root down to the matched page:
Root layout.tsx - ClerkProvider, ThemeProvider, AppToaster
└─ (app)/layout.tsx - RootLayoutClient (auth gate), Navbar
└─ page.tsx - the actual page contentFor auth routes the path is different:
Root layout.tsx - ClerkProvider, ThemeProvider, AppToaster
└─ (auth)/layout.tsx - bare <>{children}</> - no gate, no navbar
└─ sign-in/ - Clerk's sign-in UIThis is why the auth gate lives in (app)/layout.tsx and not in the root
layout.tsx. If the gate were in the root layout it would intercept every
route - including sign-in - and redirect to /sign-in forever.
Never put auth gating in the root layout.tsx. It runs on every route
including the auth pages themselves, causing an infinite redirect loop. Gate
only in the (app)/ layout.
Adding a new page
New authenticated pages go inside (app)/:
Adding a new route group
Add a new route group when a set of pages needs a different layout from the rest of the app - a public marketing section, a full-screen onboarding flow, or an admin panel with a sidebar.
Each group gets its own layout.tsx. The root layout.tsx only provides
global providers - it never makes assumptions about which group is rendering.
Shared layout elements - navbars, sidebars, footers - belong in the relevant group layout, not on individual pages.