--- trigger: glob glob: app/*.tsx,app/*jsx --- | No | Category | Guideline | Description | Do | Don't | Code Good | Code Bad | Severity | Docs URL | |----|----------|-----------|-------------|----|-------|-----------|----------|----------|----------| | 1 | Routing | Use App Router for new projects | App Router is the recommended approach in Next.js 14+ | app/ directory with page.tsx | pages/ for new projects | app/dashboard/page.tsx | pages/dashboard.tsx | Medium | https://nextjs.org/docs/app | | 2 | Routing | Use file-based routing | Create routes by adding files in app directory | page.tsx for routes layout.tsx for layouts | Manual route configuration | app/blog/[slug]/page.tsx | Custom router setup | Medium | https://nextjs.org/docs/app/building-your-application/routing | | 3 | Routing | Colocate related files | Keep components styles tests with their routes | Component files alongside page.tsx | Separate components folder | app/dashboard/_components/ | components/dashboard/ | Low | | | 4 | Routing | Use route groups for organization | Group routes without affecting URL | Parentheses for route groups | Nested folders affecting URL | (marketing)/about/page.tsx | marketing/about/page.tsx | Low | https://nextjs.org/docs/app/building-your-application/routing/route-groups | | 5 | Routing | Handle loading states | Use loading.tsx for route loading UI | loading.tsx alongside page.tsx | Manual loading state management | app/dashboard/loading.tsx | useState for loading in page | Medium | https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming | | 6 | Routing | Handle errors with error.tsx | Catch errors at route level | error.tsx with reset function | try/catch in every component | app/dashboard/error.tsx | try/catch in page component | High | https://nextjs.org/docs/app/building-your-application/routing/error-handling | | 7 | Rendering | Use Server Components by default | Server Components reduce client JS bundle | Keep components server by default | Add 'use client' unnecessarily | export default function Page() | ('use client') for static content | High | https://nextjs.org/docs/app/building-your-application/rendering/server-components | | 8 | Rendering | Mark Client Components explicitly | 'use client' for interactive components | Add 'use client' only when needed | Server Component with hooks/events | ('use client') for onClick useState | No directive with useState | High | https://nextjs.org/docs/app/building-your-application/rendering/client-components | | 9 | Rendering | Push Client Components down | Keep Client Components as leaf nodes | Client wrapper for interactive parts only | Mark page as Client Component | in Server Page | ('use client') on page.tsx | High | | | 10 | Rendering | Use streaming for better UX | Stream content with Suspense boundaries | Suspense for slow data fetches | Wait for all data before render | | await allData then render | Medium | https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming | | 11 | Rendering | Choose correct rendering strategy | SSG for static SSR for dynamic ISR for semi-static | generateStaticParams for known paths | SSR for static content | export const revalidate = 3600 | fetch without cache config | Medium | | | 12 | DataFetching | Fetch data in Server Components | Fetch directly in async Server Components | async function Page() { const data = await fetch() } | useEffect for initial data | const data = await fetch(url) | useEffect(() => fetch(url)) | High | https://nextjs.org/docs/app/building-your-application/data-fetching | | 13 | DataFetching | Configure caching explicitly (Next.js 15+) | Next.js 15 changed defaults to uncached for fetch | Explicitly set cache: 'force-cache' for static data | Assume default is cached (it's not in Next.js 15) | fetch(url, { cache: 'force-cache' }) | fetch(url) // Uncached in v15 | High | https://nextjs.org/docs/app/building-your-application/upgrading/version-15 | | 14 | DataFetching | Deduplicate fetch requests | React and Next.js dedupe same requests | Same fetch call in multiple components | Manual request deduplication | Multiple components fetch same URL | Custom cache layer | Low | | | 15 | DataFetching | Use Server Actions for mutations | Server Actions for form submissions | action={serverAction} in forms | API route for every mutation |
| | Medium | https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations | | 16 | DataFetching | Revalidate data appropriately | Use revalidatePath/revalidateTag after mutations | Revalidate after Server Action | 'use client' with manual refetch | revalidatePath('/posts') | router.refresh() everywhere | Medium | https://nextjs.org/docs/app/building-your-application/caching#revalidating | | 17 | Images | Use next/image for optimization | Automatic image optimization and lazy loading | component for all images | tags directly | {} | | High | https://nextjs.org/docs/app/building-your-application/optimizing/images | | 18 | Images | Provide width and height | Prevent layout shift with dimensions | width and height props or fill | Missing dimensions | | | High | | | 19 | Images | Use fill for responsive images | Fill container with object-fit | fill prop with relative parent | Fixed dimensions for responsive | | | Medium | | | 20 | Images | Configure remote image domains | Whitelist external image sources | remotePatterns in next.config.js | Allow all domains | remotePatterns: [{ hostname: 'cdn.example.com' }] | domains: ['*'] | High | https://nextjs.org/docs/app/api-reference/components/image#remotepatterns | | 21 | Images | Use priority for LCP images | Mark above-fold images as priority | priority prop on hero images | All images with priority | | on every image | Medium | | | 22 | Fonts | Use next/font for fonts | Self-hosted fonts with zero layout shift | next/font/google or next/font/local | External font links | import { Inter } from 'next/font/google' | | Medium | https://nextjs.org/docs/app/building-your-application/optimizing/fonts | | 23 | Fonts | Apply font to layout | Set font in root layout for consistency | className on body in layout.tsx | Font in individual pages | | Each page imports font | Low | | | 24 | Fonts | Use variable fonts | Variable fonts reduce bundle size | Single variable font file | Multiple font weights as files | Inter({ subsets: ['latin'] }) | Inter_400 Inter_500 Inter_700 | Low | | | 25 | Metadata | Use generateMetadata for dynamic | Generate metadata based on params | export async function generateMetadata() | Hardcoded metadata everywhere | generateMetadata({ params }) | export const metadata = {} | Medium | https://nextjs.org/docs/app/building-your-application/optimizing/metadata | | 26 | Metadata | Include OpenGraph images | Add OG images for social sharing | opengraph-image.tsx or og property | Missing social preview images | opengraph: { images: ['/og.png'] } | No OG configuration | Medium | | | 27 | Metadata | Use metadata API | Export metadata object for static metadata | export const metadata = {} | Manual head tags | export const metadata = { title: 'Page' } | Page | Medium | | | 28 | API | Use Route Handlers for APIs | app/api routes for API endpoints | app/api/users/route.ts | pages/api for new projects | export async function GET(request) | export default function handler | Medium | https://nextjs.org/docs/app/building-your-application/routing/route-handlers | | 29 | API | Return proper Response objects | Use NextResponse for API responses | NextResponse.json() for JSON | Plain objects or res.json() | return NextResponse.json({ data }) | return { data } | Medium | | | 30 | API | Handle HTTP methods explicitly | Export named functions for methods | Export GET POST PUT DELETE | Single handler for all methods | export async function POST() | switch(req.method) | Low | | | 31 | API | Validate request body | Validate input before processing | Zod or similar for validation | Trust client input | const body = schema.parse(await req.json()) | const body = await req.json() | High | | | 32 | Middleware | Use middleware for auth | Protect routes with middleware.ts | middleware.ts at root | Auth check in every page | export function middleware(request) | if (!session) redirect in page | Medium | https://nextjs.org/docs/app/building-your-application/routing/middleware | | 33 | Middleware | Match specific paths | Configure middleware matcher | config.matcher for specific routes | Run middleware on all routes | matcher: ['/dashboard/:path*'] | No matcher config | Medium | | | 34 | Middleware | Keep middleware edge-compatible | Middleware runs on Edge runtime | Edge-compatible code only | Node.js APIs in middleware | Edge-compatible auth check | fs.readFile in middleware | High | | | 35 | Environment | Use NEXT_PUBLIC prefix | Client-accessible env vars need prefix | NEXT_PUBLIC_ for client vars | Server vars exposed to client | NEXT_PUBLIC_API_URL | API_SECRET in client code | High | https://nextjs.org/docs/app/building-your-application/configuring/environment-variables | | 36 | Environment | Validate env vars | Check required env vars exist | Validate on startup | Undefined env at runtime | if (!process.env.DATABASE_URL) throw | process.env.DATABASE_URL (might be undefined) | High | | | 37 | Environment | Use .env.local for secrets | Local env file for development secrets | .env.local gitignored | Secrets in .env committed | .env.local with secrets | .env with DATABASE_PASSWORD | High | | | 38 | Performance | Analyze bundle size | Use @next/bundle-analyzer | Bundle analyzer in dev | Ship large bundles blindly | ANALYZE=true npm run build | No bundle analysis | Medium | https://nextjs.org/docs/app/building-your-application/optimizing/bundle-analyzer | | 39 | Performance | Use dynamic imports | Code split with next/dynamic | dynamic() for heavy components | Import everything statically | const Chart = dynamic(() => import('./Chart')) | import Chart from './Chart' | Medium | https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading | | 40 | Performance | Avoid layout shifts | Reserve space for dynamic content | Skeleton loaders aspect ratios | Content popping in | | No placeholder for async content | High | | | 41 | Performance | Use Partial Prerendering | Combine static and dynamic in one route | Static shell with Suspense holes | Full dynamic or static pages | Static header + dynamic content | Entire page SSR | Low | https://nextjs.org/docs/app/building-your-application/rendering/partial-prerendering | | 42 | Link | Use next/link for navigation | Client-side navigation with prefetching | for internal links | for internal navigation | About | About | High | https://nextjs.org/docs/app/api-reference/components/link | | 43 | Link | Prefetch strategically | Control prefetching behavior | prefetch={false} for low-priority | Prefetch all links | | Default prefetch on every link | Low | | | 44 | Link | Use scroll option appropriately | Control scroll behavior on navigation | scroll={false} for tabs pagination | Always scroll to top | | Manual scroll management | Low | | | 45 | Config | Use next.config.js correctly | Configure Next.js behavior | Proper config options | Deprecated or wrong options | images: { remotePatterns: [] } | images: { domains: [] } | Medium | https://nextjs.org/docs/app/api-reference/next-config-js | | 46 | Config | Enable strict mode | Catch potential issues early | reactStrictMode: true | Strict mode disabled | reactStrictMode: true | reactStrictMode: false | Medium | | | 47 | Config | Configure redirects and rewrites | Use config for URL management | redirects() rewrites() in config | Manual redirect handling | redirects: async () => [...] | res.redirect in pages | Medium | https://nextjs.org/docs/app/api-reference/next-config-js/redirects | | 48 | Deployment | Use Vercel for easiest deploy | Vercel optimized for Next.js | Deploy to Vercel | Self-host without knowledge | vercel deploy | Complex Docker setup for simple app | Low | https://nextjs.org/docs/app/building-your-application/deploying | | 49 | Deployment | Configure output for self-hosting | Set output option for deployment target | output: 'standalone' for Docker | Default output for containers | output: 'standalone' | No output config for Docker | Medium | https://nextjs.org/docs/app/building-your-application/deploying#self-hosting | | 50 | Security | Sanitize user input | Never trust user input | Escape sanitize validate all input | Direct interpolation of user data | DOMPurify.sanitize(userInput) | dangerouslySetInnerHTML={{ __html: userInput }} | High | | | 51 | Security | Use CSP headers | Content Security Policy for XSS protection | Configure CSP in next.config.js | No security headers | headers() with CSP | No CSP configuration | High | https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy | | 52 | Security | Validate Server Action input | Server Actions are public endpoints | Validate and authorize in Server Action | Trust Server Action input | Auth check + validation in action | Direct database call without check | High | |