Next.js Best Practices
Apply these rules when writing or reviewing Next.js code.
File Conventions
See file-conventions.md for:
- Project structure and special files
- Route segments (dynamic, catch-all, groups)
- Parallel and intercepting routes
- Middleware rename in v16 (middleware → proxy)
RSC Boundaries
Detect invalid React Server Component patterns.
See rsc-boundaries.md for:
- Async client component detection (invalid)
- Non-serializable props detection
- Server Action exceptions
Async Patterns
Next.js 15+ async API changes.
See async-patterns.md for:
- Async
params and searchParams
- Async
cookies() and headers()
- Migration codemod
Runtime Selection
See runtime-selection.md for:
- Default to Node.js runtime
- When Edge runtime is appropriate
Directives
See directives.md for:
'use client', 'use server' (React)
'use cache' (Next.js)
Functions
See functions.md for:
- Navigation hooks:
useRouter, usePathname, useSearchParams, useParams
- Server functions:
cookies, headers, draftMode, after
- Generate functions:
generateStaticParams, generateMetadata
Error Handling
See error-handling.md for:
error.tsx, global-error.tsx, not-found.tsx
redirect, permanentRedirect, notFound
forbidden, unauthorized (auth errors)
unstable_rethrow for catch blocks
Data Patterns
See data-patterns.md for:
- Server Components vs Server Actions vs Route Handlers
- Avoiding data waterfalls (
Promise.all, Suspense, preload)
- Client component data fetching
Route Handlers
See route-handlers.md for:
route.ts basics
- GET handler conflicts with
page.tsx
- Environment behavior (no React DOM)
- When to use vs Server Actions
Metadata & OG Images
See metadata.md for:
- Static and dynamic metadata
generateMetadata function
- OG image generation with
next/og
- File-based metadata conventions
Image Optimization
See image.md for:
- Always use
next/image over <img>
- Remote images configuration
- Responsive
sizes attribute
- Blur placeholders
- Priority loading for LCP
Font Optimization
See font.md for:
next/font setup
- Google Fonts, local fonts
- Tailwind CSS integration
- Preloading subsets
Bundling
See bundling.md for:
- Server-incompatible packages
- CSS imports (not link tags)
- Polyfills (already included)
- ESM/CommonJS issues
- Bundle analysis
Scripts
See scripts.md for:
next/script vs native script tags
- Inline scripts need
id
- Loading strategies
- Google Analytics with
@next/third-parties
Hydration Errors
See hydration-error.md for:
- Common causes (browser APIs, dates, invalid HTML)
- Debugging with error overlay
- Fixes for each cause
Suspense Boundaries
See suspense-boundaries.md for:
- CSR bailout with
useSearchParams and usePathname
- Which hooks require Suspense boundaries
Parallel & Intercepting Routes
See parallel-routes.md for:
- Modal patterns with
@slot and (.) interceptors
default.tsx for fallbacks
- Closing modals correctly with
router.back()
Self-Hosting
See self-hosting.md for:
output: 'standalone' for Docker
- Cache handlers for multi-instance ISR
- What works vs needs extra setup
Debug Tricks
See debug-tricks.md for:
- MCP endpoint for AI-assisted debugging
- Rebuild specific routes with
--debug-build-paths
1---
2name: nextjs
3description: Next.js App Router expert guidance. Use when building, debugging, or architecting Next.js applications — routing, Server Components, Server Actions, Cache Components, layouts, middleware/proxy, data fetching, rendering strategies, and deployment on Vercel.
4metadata:
5 priority: 5
6 docs:
7 - "https://nextjs.org/docs"
8 - "https://nextjs.org/docs/app"
9 sitemap: "https://nextjs.org/sitemap.xml"
10 pathPatterns:
11 - 'next.config.*'
12 - 'next-env.d.ts'
13 - 'app/**'
14 - 'pages/**'
15 - 'src/app/**'
16 - 'src/pages/**'
17 - 'tailwind.config.*'
18 - 'postcss.config.*'
19 - 'tsconfig.json'
20 - 'tsconfig.*.json'
21 - 'apps/*/app/**'
22 - 'apps/*/pages/**'
23 - 'apps/*/src/app/**'
24 - 'apps/*/src/pages/**'
25 - 'apps/*/next.config.*'
26 bashPatterns:
27 - '\bnext\s+(dev|build|start|lint)\b'
28 - '\bnext\s+experimental-analyze\b'
29 - '\bnpx\s+create-next-app\b'
30 - '\bbunx\s+create-next-app\b'
31 - '\bnpm\s+run\s+(dev|build|start)\b'
32 - '\bpnpm\s+(dev|build)\b'
33 - '\bbun\s+run\s+(dev|build)\b'
34 promptSignals:
35 phrases:
36 - "next.js"
37 - "nextjs"
38 - "app router"
39 - "server component"
40 - "server action"
41 allOf:
42 - [middleware, next]
43 - [layout, route]
44 anyOf:
45 - "pages router"
46 - "getserversideprops"
47 - "use server"
48 noneOf: []
49 minScore: 6
50validate:
51 -
52 pattern: export.*getServerSideProps
53 message: 'getServerSideProps is removed in App Router — use server components or route handlers'
54 severity: error
55 upgradeToSkill: nextjs
56 upgradeWhy: 'Guides migration from Pages Router getServerSideProps to App Router server components with async data fetching.'
57 -
58 pattern: getServerSideProps
59 message: 'getServerSideProps is a Pages Router pattern — migrate to App Router server components'
60 severity: warn
61 -
62 pattern: export.*getStaticProps
63 message: 'getStaticProps is removed in App Router — use generateStaticParams + server components instead'
64 severity: error
65 upgradeToSkill: nextjs
66 upgradeWhy: 'Guides migration from Pages Router getStaticProps to App Router generateStaticParams with server components.'
67 -
68 pattern: getStaticProps
69 message: 'getStaticProps is a Pages Router pattern — migrate to App Router generateStaticParams + server components'
70 severity: warn
71 -
72 pattern: from\s+['"]next/router['"]
73 message: 'next/router is Pages Router only — use next/navigation for App Router'
74 severity: error
75 upgradeToSkill: nextjs
76 upgradeWhy: 'Guides migration from next/router to next/navigation with useRouter, usePathname, useSearchParams hooks.'
77 -
78 pattern: (useState|useEffect)
79 message: 'React hooks require "use client" directive — add it at the top of client components'
80 severity: warn
81 skipIfFileContains: "^['\"]use client['\"]"
82 -
83 pattern: from\s+['"]next/head['"]
84 message: 'next/head is Pages Router — use export const metadata or generateMetadata() in App Router. Run Skill(nextjs) for metadata API guidance.'
85 severity: error
86 upgradeToSkill: nextjs
87 upgradeWhy: 'Guides migration from next/head to the App Router metadata API (export const metadata / generateMetadata()).'
88 skipIfFileContains: export\s+(const\s+)?metadata|generateMetadata
89 -
90 pattern: export\s+(default\s+)?function\s+middleware
91 message: 'middleware() is renamed to proxy() in Next.js 16 — rename the function and the file to proxy.ts. Run Skill(routing-middleware) for proxy.ts migration guidance.'
92 severity: recommended
93 upgradeToSkill: routing-middleware
94 upgradeWhy: 'Guides migration from middleware.ts to proxy.ts with correct file placement, runtime config, and request interception patterns.'
95 -
96 pattern: revalidateTag\(\s*['"][^'"]+['"]\s*\)
97 message: 'Single-arg revalidateTag(tag) is deprecated in Next.js 16 — pass a cacheLife profile: revalidateTag(tag, "max")'
98 severity: recommended
99 upgradeToSkill: nextjs
100 upgradeWhy: 'Guides migration from single-arg revalidateTag to the Next.js 16 two-arg API with cacheLife profiles.'
101 -
102 pattern: '\bcacheHandler\s*:'
103 message: 'Singular cacheHandler is deprecated in Next.js 16 — use cacheHandlers (plural) with per-type handlers'
104 severity: recommended
105 upgradeToSkill: nextjs
106 upgradeWhy: 'Guides migration from singular cacheHandler to Next.js 16 cacheHandlers (plural) with per-type handler config.'
107 -
108 pattern: useRef\(\s*\)
109 message: 'useRef() requires an initial value in React 19 — use useRef(null) or useRef(0)'
110 severity: error
111 -
112 pattern: next\s+export
113 message: 'next export was removed — use output: "export" in next.config.js for static export'
114 severity: error
115 upgradeToSkill: nextjs
116 upgradeWhy: 'Guides migration from next export CLI command to output: "export" in next.config for static site generation.'
117 -
118 pattern: (?<!await )\bcookies\(\s*\)
119 message: 'cookies() is async in Next.js 16 — add await: const cookieStore = await cookies()'
120 severity: error
121 skipIfFileContains: "^['\"]use client['\"]"
122 -
123 pattern: (?<!await )\bheaders\(\s*\)
124 message: 'headers() is async in Next.js 16 — add await: const headersList = await headers()'
125 severity: error
126 skipIfFileContains: "^['\"]use client['\"]"
127 -
128 pattern: =\s*(?!await\b)params\b
129 message: 'params is async in Next.js 16 — add await: const { slug } = await params'
130 severity: recommended
131 skipIfFileContains: "^['\"]use client['\"]"
132 -
133 pattern: =\s*(?!await\b)searchParams\b
134 message: 'searchParams is async in Next.js 16 — add await: const { query } = await searchParams'
135 severity: recommended
136 skipIfFileContains: "^['\"]use client['\"]"
137 -
138 pattern: 'from\s+[''""](next-auth|@auth/core)[''""]|NextAuth\(|getServerSession\('
139 message: 'Legacy auth pattern detected. Modern Vercel apps should use Clerk, Descope, or Auth0 for managed authentication.'
140 severity: recommended
141 upgradeToSkill: auth
142 upgradeWhy: 'Migrate from next-auth/manual JWT to a managed auth provider (Clerk, Descope, Auth0) for better Vercel integration.'
143 skipIfFileContains: '@clerk/|@descope/|@auth0/'
144 -
145 pattern: 'NextApiRequest|NextApiResponse|export\s+default\s+function\s+handler'
146 message: 'Pages Router API handler detected. Use App Router route handlers with named HTTP exports instead.'
147 severity: recommended
148 upgradeToSkill: vercel-functions
149 upgradeWhy: 'Migrate from Pages Router API routes to App Router route handlers with Web Request/Response API.'
150 skipIfFileContains: 'export\s+(async\s+)?function\s+(GET|POST|PUT|PATCH|DELETE)'
151 -
152 pattern: 'from\s+[''""](lru-cache|node-cache|memory-cache)[''""]|new\s+(LRUCache|NodeCache)\('
153 message: 'In-process cache detected. Serverless deployments lose process memory between invocations.'
154 severity: recommended
155 upgradeToSkill: runtime-cache
156 upgradeWhy: 'Replace process-memory caches with Vercel Runtime Cache for shared, region-aware caching.'
157 -
158 pattern: 'from\s+[''""](express|fastify|koa|hapi)[''""]|require\s*\(\s*[''""](express|fastify|koa|hapi)[''""]'
159 message: 'Express/Fastify/Koa/Hapi server framework detected in a Next.js project. Use Next.js route handlers or proxy.ts for request handling instead.'
160 severity: recommended
161 upgradeToSkill: routing-middleware
162 upgradeWhy: 'Replace custom server frameworks with Next.js proxy.ts for request interception and route handlers for API endpoints.'
163 skipIfFileContains: 'proxy\.ts|from\s+[''""](next/server)[''""]|@vercel/functions'
164 -
165 pattern: 'from\s+[''""](typeorm|sequelize|mikro-orm|objection|bookshelf|knex)[''""]|require\s*\(\s*[''""](typeorm|sequelize|mikro-orm|objection|bookshelf|knex)[''""]'
166 message: 'Heavy ORM detected. Consider using lightweight serverless-native alternatives like Drizzle, Prisma, or direct Neon for better cold start performance.'
167 severity: recommended
168 upgradeToSkill: vercel-storage
169 upgradeWhy: 'Migrate from heavy ORMs to serverless-native database clients (Drizzle + Neon, Prisma, or @neondatabase/serverless) for faster cold starts.'
170 skipIfFileContains: 'from\s+[''""](drizzle-orm|@neondatabase|@prisma/client|prisma)[''""]'
171 -
172 pattern: 'fonts\.googleapis\.com|from\s+[''""](fontsource|@fontsource)[''""]|<link[^>]*fonts\.googleapis'
173 message: 'External font loader detected. Use next/font for zero-CLS, self-hosted font loading with automatic optimization.'
174 severity: recommended
175 upgradeToSkill: nextjs
176 upgradeWhy: 'Guides migration from external font loaders to next/font with Geist Sans/Mono for zero-CLS font optimization.'
177 skipIfFileContains: 'next/font'
178chainTo:
179 -
180 pattern: 'export\s+(default\s+)?function\s+middleware'
181 targetSkill: routing-middleware
182 message: 'middleware() is renamed to proxy() in Next.js 16 — loading Routing Middleware guidance for proxy.ts migration.'
183 -
184 pattern: "from\\s+['\"]@vercel/(postgres|kv)['\"]"
185 targetSkill: vercel-storage
186 message: 'Sunset storage package detected — loading Vercel Storage guidance for Neon/Upstash migration.'
187 -
188 pattern: "from\\s+['\"]@ai-sdk/(anthropic|openai)['\"]"
189 targetSkill: ai-gateway
190 message: 'Direct AI provider SDK import — loading AI Gateway guidance for unified model routing with failover and cost tracking.'
191 -
192 pattern: 'from\s+[''""](next-auth|@auth/core)[''""]|NextAuth\(|getServerSession\('
193 targetSkill: auth
194 message: 'Legacy auth pattern detected — loading managed authentication guidance (Clerk, Descope, Auth0).'
195 -
196 pattern: 'NextApiRequest|NextApiResponse|export\s+default\s+function\s+handler'
197 targetSkill: vercel-functions
198 message: 'Pages Router API handler detected — loading Vercel Functions guidance for App Router migration.'
199 -
200 pattern: 'from\s+[''""](lru-cache|node-cache|memory-cache)[''""]|new\s+(LRUCache|NodeCache)\('
201 targetSkill: runtime-cache
202 message: 'In-process cache detected — loading Runtime Cache guidance for serverless-compatible caching.'
203 -
204 pattern: 'fetch\s*\(\s*[''""](https?://)?(api\.openai\.com|api\.anthropic\.com|api\.cohere\.ai)'
205 targetSkill: ai-gateway
206 message: 'Raw AI provider fetch URL detected — loading AI Gateway guidance for unified routing, failover, and OIDC auth.'
207 skipIfFileContains: '@ai-sdk/|from\s+[''""](ai)[''""]|ai-gateway|gateway\('
208 -
209 pattern: 'jwt\.(sign|verify|decode)\(|from\s+[''""](jsonwebtoken)[''""]|new\s+SignJWT\(|jwtVerify\('
210 targetSkill: auth
211 message: 'Manual JWT token handling detected — loading Auth guidance for managed authentication (Clerk, Descope, Auth0).'
212 skipIfFileContains: 'clerkMiddleware|@clerk/|@auth0/|@descope/|from\s+[''""](next-auth)[''""]'
213 -
214 pattern: 'from\s+[''"]@/components/ui/|from\s+[''"]@/components/ui[''""]'
215 targetSkill: shadcn
216 message: 'shadcn/ui component imports detected — loading shadcn guidance for component composition, theming, and registry patterns.'
217 skipIfFileContains: 'shadcn|components\.json'
218 -
219 pattern: 'from\s+[''""](styled-components|@emotion/(react|styled)|@mui/material)[''""]'
220 targetSkill: shadcn
221 message: 'CSS-in-JS library detected — loading shadcn/ui guidance for Tailwind CSS + Radix UI component patterns (Vercel recommended).'
222 skipIfFileContains: '@/components/ui|shadcn'
223 -
224 pattern: 'getInitialProps'
225 targetSkill: nextjs
226 message: 'getInitialProps is a legacy Pages Router pattern — loading Next.js guidance for App Router migration with server components and async data fetching.'
227 skipIfFileContains: 'app/.*page\.|generateStaticParams|use cache'
228 -
229 pattern: 'export.*getServerSideProps|getServerSideProps\s*\('
230 targetSkill: nextjs
231 message: 'getServerSideProps is a Pages Router pattern — loading Next.js guidance for App Router migration with server components and async data fetching.'
232 skipIfFileContains: 'generateStaticParams|use cache|app/.*page\.'
233 -
234 pattern: 'export.*getStaticProps|getStaticProps\s*\('
235 targetSkill: nextjs
236 message: 'getStaticProps is a Pages Router pattern — loading Next.js guidance for App Router migration with generateStaticParams and server components.'
237 skipIfFileContains: 'generateStaticParams|use cache|app/.*page\.'
238 -
239 pattern: '_app\.(tsx?|jsx?)'
240 targetSkill: nextjs
241 message: '_app.tsx is a Pages Router pattern — loading Next.js guidance for App Router layout.tsx migration.'
242 skipIfFileContains: 'app/layout\.|app/.*layout\.'
243 -
244 pattern: '_document\.(tsx?|jsx?)'
245 targetSkill: nextjs
246 message: '_document.tsx is a Pages Router pattern — loading Next.js guidance for App Router layout.tsx with metadata API migration.'
247 skipIfFileContains: 'app/layout\.|app/.*layout\.'
248 -
249 pattern: "from\\s+['\"]next/document['\"]"
250 targetSkill: nextjs
251 message: 'next/document is Pages Router only — loading Next.js guidance for App Router layout.tsx with html/body structure.'
252 skipIfFileContains: 'app/layout\.|app/.*layout\.'
253 -
254 pattern: 'pages/api/'
255 targetSkill: vercel-functions
256 message: 'Pages Router API route (pages/api/) detected — loading Vercel Functions guidance for App Router route handlers with named HTTP exports.'
257 skipIfFileContains: 'export\s+(async\s+)?function\s+(GET|POST|PUT|PATCH|DELETE)'
258retrieval:
259 aliases:
260 - next.js
261 - nextjs app
262 - react framework
263 - app router
264 intents:
265 - set up routing and layouts in a Next.js app
266 - choose between server and client components for a feature
267 - configure data fetching or caching in App Router
268 - add middleware or proxy logic to handle requests
269 - set up server rendering for React pages
270 - add a new page with dynamic route segments
271 entities:
272 - App Router
273 - Server Components
274 - Server Actions
275 - generateMetadata
276 - layout
277 - proxy
278 - next.config
279 examples:
280 - add a new page with dynamic routing
281 - should this be a server or client component
282 - set up middleware for auth redirects
283 - configure caching for this data fetch
284 - set up server rendering for my pages
285
286---
287
288# Next.js Best Practices
289
290Apply these rules when writing or reviewing Next.js code.
291
292## File Conventions
293
294See [file-conventions.md](./file-conventions.md) for:
295- Project structure and special files
296- Route segments (dynamic, catch-all, groups)
297- Parallel and intercepting routes
298- Middleware rename in v16 (middleware → proxy)
299
300## RSC Boundaries
301
302Detect invalid React Server Component patterns.
303
304See [rsc-boundaries.md](./rsc-boundaries.md) for:
305- Async client component detection (invalid)
306- Non-serializable props detection
307- Server Action exceptions
308
309## Async Patterns
310
311Next.js 15+ async API changes.
312
313See [async-patterns.md](./async-patterns.md) for:
314- Async `params` and `searchParams`
315- Async `cookies()` and `headers()`
316- Migration codemod
317
318## Runtime Selection
319
320See [runtime-selection.md](./runtime-selection.md) for:
321- Default to Node.js runtime
322- When Edge runtime is appropriate
323
324## Directives
325
326See [directives.md](./directives.md) for:
327- `'use client'`, `'use server'` (React)
328- `'use cache'` (Next.js)
329
330## Functions
331
332See [functions.md](./functions.md) for:
333- Navigation hooks: `useRouter`, `usePathname`, `useSearchParams`, `useParams`
334- Server functions: `cookies`, `headers`, `draftMode`, `after`
335- Generate functions: `generateStaticParams`, `generateMetadata`
336
337## Error Handling
338
339See [error-handling.md](./error-handling.md) for:
340- `error.tsx`, `global-error.tsx`, `not-found.tsx`
341- `redirect`, `permanentRedirect`, `notFound`
342- `forbidden`, `unauthorized` (auth errors)
343- `unstable_rethrow` for catch blocks
344
345## Data Patterns
346
347See [data-patterns.md](./data-patterns.md) for:
348- Server Components vs Server Actions vs Route Handlers
349- Avoiding data waterfalls (`Promise.all`, Suspense, preload)
350- Client component data fetching
351
352## Route Handlers
353
354See [route-handlers.md](./route-handlers.md) for:
355- `route.ts` basics
356- GET handler conflicts with `page.tsx`
357- Environment behavior (no React DOM)
358- When to use vs Server Actions
359
360## Metadata & OG Images
361
362See [metadata.md](./metadata.md) for:
363- Static and dynamic metadata
364- `generateMetadata` function
365- OG image generation with `next/og`
366- File-based metadata conventions
367
368## Image Optimization
369
370See [image.md](./image.md) for:
371- Always use `next/image` over `<img>`
372- Remote images configuration
373- Responsive `sizes` attribute
374- Blur placeholders
375- Priority loading for LCP
376
377## Font Optimization
378
379See [font.md](./font.md) for:
380- `next/font` setup
381- Google Fonts, local fonts
382- Tailwind CSS integration
383- Preloading subsets
384
385## Bundling
386
387See [bundling.md](./bundling.md) for:
388- Server-incompatible packages
389- CSS imports (not link tags)
390- Polyfills (already included)
391- ESM/CommonJS issues
392- Bundle analysis
393
394## Scripts
395
396See [scripts.md](./scripts.md) for:
397- `next/script` vs native script tags
398- Inline scripts need `id`
399- Loading strategies
400- Google Analytics with `@next/third-parties`
401
402## Hydration Errors
403
404See [hydration-error.md](./hydration-error.md) for:
405- Common causes (browser APIs, dates, invalid HTML)
406- Debugging with error overlay
407- Fixes for each cause
408
409## Suspense Boundaries
410
411See [suspense-boundaries.md](./suspense-boundaries.md) for:
412- CSR bailout with `useSearchParams` and `usePathname`
413- Which hooks require Suspense boundaries
414
415## Parallel & Intercepting Routes
416
417See [parallel-routes.md](./parallel-routes.md) for:
418- Modal patterns with `@slot` and `(.)` interceptors
419- `default.tsx` for fallbacks
420- Closing modals correctly with `router.back()`
421
422## Self-Hosting
423
424See [self-hosting.md](./self-hosting.md) for:
425- `output: 'standalone'` for Docker
426- Cache handlers for multi-instance ISR
427- What works vs needs extra setup
428
429## Debug Tricks
430
431See [debug-tricks.md](./debug-tricks.md) for:
432- MCP endpoint for AI-assisted debugging
433- Rebuild specific routes with `--debug-build-paths`
434