Route groups organize routes without affecting URLs. Middleware runs before a request completes—ideal for auth redirects, geo headers, and A/B flags at the edge.
Route groups
app/
(marketing)/
about/page.tsx → /about
pricing/page.tsx → /pricing
(app)/
dashboard/page.tsx → /dashboard
Parentheses strip the group name from the URL—purely for file organization and shared layouts per group.
middleware.ts
project-root/
middleware.ts # not inside app/
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
if (!request.cookies.get('session')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = { matcher: ['/dashboard/:path*'] };
When to use which
- Route group layout — different shells for marketing vs app chrome
- Middleware — cheap checks before render (auth, locale prefix, bot blocking)
- Server Component — data-heavy auth that needs database lookups
Self-check
- Does
(shop)appear in the browser URL? - Why not put all auth logic only in middleware?
Interview prep
- When use middleware?
Edge checks before render—auth redirects, locale, A/B flags—not heavy database business logic (use Server Components for that).