skills/masanao-ohba/claude-manifests/nextjs-code-reviewer

nextjs-code-reviewer

SKILL.md

Next.js Code Review Guidelines

App Router Structure

File Organization

Issues:

  • page.tsx missing in route directory (route won't work)
  • layout.tsx not at app root (required)
  • Client Component marked with 'use client' unnecessarily
  • API route in wrong location (should be in app/api/)
  • Special files (loading, error, not-found) in wrong location

Verify:

  • Root layout.tsx exists and returns <html> and <body>
  • Each route directory has page.tsx for that route
  • loading.tsx and error.tsx placed at appropriate levels
  • API routes follow app/api/* convention

Server vs Client

Critical Issues:

  • 'use client' on component that doesn't need it
  • Server Component trying to use hooks
  • Client Component doing data fetching (should be Server Component)
  • Sensitive data (API keys, secrets) in Client Components

Verify:

  • Default to Server Components
  • 'use client' only for: hooks, event handlers, browser APIs, Context
  • Data fetching in Server Components when possible
  • Client Components receive data as props

Data Fetching

Server Components

Issues:

  • Using useEffect for data fetching (should be async/await)
  • Not handling errors with try-catch
  • Fetching inside loops (N+1 problem)
  • Not using Promise.all for parallel fetches
  • Missing revalidation strategy

Verify:

  • Async functions for data fetching
  • Proper error handling
  • Parallel fetching with Promise.all when possible
  • Appropriate cache strategy (force-cache, no-store, revalidate)

Client Components

Issues:

  • Using fetch in useEffect instead of React Query
  • Not handling loading and error states
  • Race conditions in useEffect
  • Missing error boundaries

Verify:

  • React Query for client-side data fetching
  • Loading, error, and success states all handled
  • Proper query key structure
  • Error boundaries in place

Routing

Dynamic Routes

Issues:

  • Not validating params before use
  • Not handling missing data (404 cases)
  • Missing generateStaticParams for static export
  • Params not properly typed

Verify:

  • Params validated and typed correctly
  • notFound() called for missing resources
  • generateStaticParams implemented for SSG
  • Type safety: { params: { slug: string } }

Navigation

Issues:

  • Using <a> instead of <Link>
  • Using router.push with full URL (should be relative)
  • Not using prefetch for important links
  • Client-side navigation for external links

Verify:

  • <Link> component for internal navigation
  • Relative paths in navigation
  • prefetch={true} for critical routes
  • <a> with rel="noopener noreferrer" for external links

Loading States

Suspense

Issues:

  • No loading.tsx at route level
  • No fallback for Suspense boundaries
  • Loading state only shows after delay (missing instant feedback)
  • Suspense boundaries too coarse-grained

Verify:

  • loading.tsx provides meaningful loading UI
  • Suspense boundaries around async components
  • Instant loading feedback
  • Multiple Suspense boundaries for granular loading

Error Handling

Error Boundaries

Issues:

  • No error.tsx at route level
  • Error component not marked 'use client'
  • Error messages expose sensitive information
  • No retry mechanism in error UI
  • Not using error.digest for error tracking

Verify:

  • error.tsx in place for each route segment
  • 'use client' directive on error components
  • User-friendly error messages
  • Reset function provided to users
  • Error logging/tracking implemented

Not Found

Issues:

  • 404 errors not handled gracefully
  • notFound() not called for missing resources
  • Generic 404 page for all routes

Verify:

  • notFound() called when resource doesn't exist
  • Custom not-found.tsx at route level if needed
  • Clear messaging about what was not found

API Routes

Route Handlers

Issues:

  • Not validating request body
  • Missing error handling
  • Not using proper HTTP status codes
  • CORS not configured for cross-origin requests
  • No rate limiting for public endpoints

Verify:

  • Request validation with Zod or similar
  • Proper error responses with status codes
  • NextResponse.json() for responses
  • CORS headers if needed
  • Authentication checks before sensitive operations

Security

Critical Issues:

  • SQL injection vulnerabilities
  • No authentication on protected routes
  • API keys exposed in client code
  • CSRF vulnerabilities in mutations
  • No input sanitization

Verify:

  • Parameterized queries (no string concatenation)
  • Authentication middleware on protected routes
  • Environment variables for secrets
  • CSRF protection for mutations
  • Input validation and sanitization

Server Actions

Implementation

Issues:

  • 'use server' directive missing
  • Not revalidating cache after mutations
  • No error handling
  • Not returning serializable data
  • Complex logic in server action (should be in service layer)

Verify:

  • 'use server' at file or function level
  • revalidatePath() or revalidateTag() after data changes
  • Try-catch with user-friendly error messages
  • Returned data is JSON-serializable
  • Business logic in separate service functions

Metadata and SEO

Metadata

Issues:

  • No metadata exported
  • Missing Open Graph tags
  • No Twitter Card metadata
  • Dynamic pages missing generateMetadata
  • Duplicate titles across pages

Verify:

  • Metadata object or generateMetadata function present
  • Title, description, and OG tags complete
  • Dynamic metadata for dynamic routes
  • Unique, descriptive titles for each page
  • Appropriate meta tags for social sharing

Images

Issues:

  • Using <img> instead of <Image>
  • Missing alt text
  • Not specifying width and height
  • Not using priority for LCP images
  • Remote images not configured in next.config.js

Verify:

  • next/image for all images
  • Descriptive alt text (or empty string if decorative)
  • Width and height specified (or fill mode)
  • priority prop on above-the-fold images
  • Remote image domains configured

Performance

Bundle Size

Issues:

  • Heavy libraries imported in Client Components
  • No code splitting for large features
  • All components in single file
  • Not using dynamic imports for heavy components

Verify:

  • Heavy dependencies in Server Components when possible
  • Dynamic imports for large, conditional components
  • Components split into separate files
  • Bundle analysis done regularly

Caching

Issues:

  • No caching strategy defined
  • Using no-store for everything (too aggressive)
  • Not using revalidation for stale-while-revalidate
  • Not leveraging Next.js automatic request deduplication

Verify:

  • Appropriate cache strategy per request
  • force-cache for static data
  • revalidate for time-based freshness
  • no-store only for user-specific or sensitive data

Rendering

Issues:

  • Not using Static Site Generation (SSG) when possible
  • Generating all pages at build time (slow builds)
  • Not implementing Incremental Static Regeneration (ISR)

Verify:

  • generateStaticParams for known routes
  • ISR (revalidate) for frequently changing content
  • On-demand revalidation for critical updates

TypeScript

Type Safety

Issues:

  • Params and searchParams not typed
  • API route request/response not typed
  • Server action return values not typed
  • Using 'any' for Next.js types

Verify:

  • PageProps interface for params and searchParams
  • NextRequest and NextResponse properly typed
  • Server actions have return type annotations
  • Imported Next.js types used correctly

Middleware

Implementation

Issues:

  • Heavy logic in middleware (runs on every request)
  • Not returning NextResponse
  • Middleware running on static assets
  • No matcher config (runs on all routes)

Verify:

  • Lightweight logic only (auth checks, redirects)
  • NextResponse.next() or redirect returned
  • Matcher excludes _next/static and other assets
  • Matcher config specific to needed routes

Internationalization

next-intl

Issues:

  • Locale not validated in params
  • Messages not loaded for server components
  • Hardcoded strings instead of translations
  • Missing translations causing runtime errors

Verify:

  • Locale param validated against supported locales
  • getMessages() called in server components
  • All user-facing text uses t() function
  • Fallback locale configured

Code Quality

Best Practices

Issues:

  • Mixing Server and Client code in same file
  • Deep nesting of route groups
  • No consistent naming convention
  • Component files > 500 lines

Verify:

  • Clear separation of Server and Client code
  • Reasonable route group nesting (< 3 levels)
  • Consistent file naming (kebab-case or PascalCase)
  • Components split appropriately

Review Checklist

Critical

  • Server/Client component separation correct
  • No security vulnerabilities (auth, input validation)
  • Error handling comprehensive
  • Type safety maintained

High Priority

  • Loading states implemented
  • SEO metadata complete
  • Images optimized
  • Caching strategy appropriate

Medium Priority

  • Code organization clean
  • No console.logs left in
  • Consistent code style
  • Performance optimizations justified
Weekly Installs
6
GitHub Stars
2
First Seen
Jan 29, 2026
Installed on
github-copilot5
opencode4
gemini-cli4
codex4
kimi-cli4
amp4