Next.js 14 — App Router Patterns
Purpose
Next.js 14 App Router patterns for web applications. Covers routing structure, middleware, server actions (callers), error handling, and performance optimization.
Route Structure
Uses locale-scoped route groups with auth separation:
app/
├── [locale]/ # Dynamic locale segment
│ ├── layout.tsx # Root: ReduxProvider > AuthProvider > NextIntlClientProvider
│ ├── global_error.tsx # Must include <html><body> — wraps root layout
│ ├── (auth)/ # Requires authentication session
│ │ ├── layout.tsx # Sidebar menu, session check
│ │ ├── error.tsx # Auth-level error boundary
│ │ ├── [...rest]/page.tsx # Catch-all → notFound()
│ │ ├── feature-a/
│ │ │ └── [id]/detail/[detailId]/
│ │ ├── feature-b/
│ │ │ └── [category]/
│ │ ├── feature-c/
│ │ └── feature-d/
│ └── (public)/ # No auth required
│ ├── onboarding/
│ └── error-pages/
├── api/
│ ├── auth/[...nextauth]/ # NextAuth route handler
│ ├── internal/log/ # Client→server log forwarding
│ └── proxy/ # Proxy endpoints
Conventions
_prefix folders (_components, _services, _actions, _hooks, _stores, _utils, _ui-models, _enums, _constants) — private to their route segment, not routed by Next.js
(auth) / (public) — route groups for layout scoping, invisible in URL
[...rest] under (auth) — catch-all that calls notFound() for unknown paths
Server vs Client Boundary
| Pattern |
Directive |
When |
| Server Component |
(default) |
Data fetching, layout, metadata |
| Client Component |
'use client' |
Hooks, event handlers, browser APIs, Radix UI |
| Server Action |
'use server' |
Callers in caller/ directory |
Decision tree for 'use client': Does it use useState, useEffect, useContext, event handlers, or browser APIs? → Yes = client. Otherwise leave as server component.
Server Actions — Caller Pattern
All API calls go through caller/ files with 'use server'. See web-api-routes skill for FetchBuilder details.
See web-api-routes/references/caller-patterns.md for FetchBuilder caller examples.
Error Handling
Three-level error boundary hierarchy:
| File |
Scope |
Pattern |
global_error.tsx |
Root layout crashes |
logger.error + <ErrorPage> with <html><body> wrapper |
(auth)/error.tsx |
All auth routes |
useEffect logger + <ErrorPage resetFunction={reset}> |
Feature error.tsx |
Module-level |
Same pattern — clientLogger.error + <ErrorPage> |
Shared component: app/[locale]/components/error-page.tsx — uses useTranslations, Button, and an illustration component.
FetchBuilder never throws — returns { error: { status, reason } }. Always check response.error or use isErrorResponse().
Metadata
See web-i18n skill for generateMetadata with translation patterns.
Reference Files
| File |
Purpose |
references/routing.md |
Route groups, dynamic segments, _prefix convention |
references/middleware.md |
Combined intl+auth, feature flags, request tracing |
references/performance.md |
Parallel fetching, Suspense boundaries, dynamic imports |
Sub-Skill Routing
When this skill is active and user intent matches a sub-skill, delegate:
| Intent |
Sub-Skill |
When |
| API routes |
web-api-routes |
FetchBuilder, callers, route.ts handlers |
| Module integration |
web-modules |
B2B module scaffolding |
| i18n |
web-i18n |
Translations, locale routing |
| Auth |
web-auth |
Auth, sessions, protected routes |
Rules
- All API calls through FetchBuilder — never raw
fetch() in app code (except route.ts proxies)
- Use
caller/ pattern for server actions — explicit params or session retrieval
- Error boundaries at every route group level
generateMetadata() in every layout for SEO
- Import
Link, redirect, useRouter from navigation.ts — not from next/link or next/navigation
1---2name: web-nextjs-23description: (ePost) Use when working with Next.js App Router, Server Components, Server Actions, or page/layout routing4---5
6# Next.js 14 — App Router Patterns
7
8## Purpose
9
10Next.js 14 App Router patterns for web applications. Covers routing structure, middleware, server actions (callers), error handling, and performance optimization.
11
12## Route Structure
13
14Uses locale-scoped route groups with auth separation:
15
16```
17app/
18├── [locale]/ # Dynamic locale segment
19│ ├── layout.tsx # Root: ReduxProvider > AuthProvider > NextIntlClientProvider
20│ ├── global_error.tsx # Must include <html><body> — wraps root layout
21│ ├── (auth)/ # Requires authentication session
22│ │ ├── layout.tsx # Sidebar menu, session check
23│ │ ├── error.tsx # Auth-level error boundary
24│ │ ├── [...rest]/page.tsx # Catch-all → notFound()
25│ │ ├── feature-a/
26│ │ │ └── [id]/detail/[detailId]/
27│ │ ├── feature-b/
28│ │ │ └── [category]/
29│ │ ├── feature-c/
30│ │ └── feature-d/
31│ └── (public)/ # No auth required
32│ ├── onboarding/
33│ └── error-pages/
34├── api/
35│ ├── auth/[...nextauth]/ # NextAuth route handler
36│ ├── internal/log/ # Client→server log forwarding
37│ └── proxy/ # Proxy endpoints
38```
39
40### Conventions
41
42- **`_prefix` folders** (`_components`, `_services`, `_actions`, `_hooks`, `_stores`, `_utils`, `_ui-models`, `_enums`, `_constants`) — private to their route segment, not routed by Next.js
43- **`(auth)` / `(public)`** — route groups for layout scoping, invisible in URL
44- **`[...rest]`** under `(auth)` — catch-all that calls `notFound()` for unknown paths
45
46## Server vs Client Boundary
47
48| Pattern | Directive | When |
49|---------|-----------|------|
50| Server Component | (default) | Data fetching, layout, metadata |
51| Client Component | `'use client'` | Hooks, event handlers, browser APIs, Radix UI |
52| Server Action | `'use server'` | Callers in `caller/` directory |
53
54Decision tree for `'use client'`: Does it use `useState`, `useEffect`, `useContext`, event handlers, or browser APIs? → Yes = client. Otherwise leave as server component.
55
56## Server Actions — Caller Pattern
57
58All API calls go through `caller/` files with `'use server'`. See `web-api-routes` skill for FetchBuilder details.
59
60See `web-api-routes/references/caller-patterns.md` for FetchBuilder caller examples.
61
62## Error Handling
63
64Three-level error boundary hierarchy:
65
66| File | Scope | Pattern |
67|------|-------|---------|
68| `global_error.tsx` | Root layout crashes | `logger.error` + `<ErrorPage>` with `<html><body>` wrapper |
69| `(auth)/error.tsx` | All auth routes | `useEffect` logger + `<ErrorPage resetFunction={reset}>` |
70| Feature `error.tsx` | Module-level | Same pattern — `clientLogger.error` + `<ErrorPage>` |
71
72Shared component: `app/[locale]/components/error-page.tsx` — uses `useTranslations`, `Button`, and an illustration component.
73
74**FetchBuilder never throws** — returns `{ error: { status, reason } }`. Always check `response.error` or use `isErrorResponse()`.
75
76## Metadata
77
78See `web-i18n` skill for `generateMetadata` with translation patterns.
79
80## Reference Files
81
82| File | Purpose |
83|------|---------|
84| `references/routing.md` | Route groups, dynamic segments, `_prefix` convention |
85| `references/middleware.md` | Combined intl+auth, feature flags, request tracing |
86| `references/performance.md` | Parallel fetching, Suspense boundaries, dynamic imports |
87
88## Sub-Skill Routing
89
90When this skill is active and user intent matches a sub-skill, delegate:
91
92| Intent | Sub-Skill | When |
93|--------|-----------|------|
94| API routes | `web-api-routes` | FetchBuilder, callers, route.ts handlers |
95| Module integration | `web-modules` | B2B module scaffolding |
96| i18n | `web-i18n` | Translations, locale routing |
97| Auth | `web-auth` | Auth, sessions, protected routes |
98
99## Rules
100
101- All API calls through FetchBuilder — never raw `fetch()` in app code (except route.ts proxies)
102- Use `caller/` pattern for server actions — explicit params or session retrieval
103- Error boundaries at every route group level
104- `generateMetadata()` in every layout for SEO
105- Import `Link`, `redirect`, `useRouter` from `navigation.ts` — not from `next/link` or `next/navigation`