WritingNext.js App Router Production Readiness Checklist — LinkIT
4 min readnext.js, app-router, checklist, production, performance

Next.js App Router Production Readiness Checklist

Review a Next.js App Router application before launch: component boundaries, data fetching, caching, security, performance, and monitoring.

Before launching a Next.js App Router application, check rendering boundaries, data access, cache behavior, failure states, and monitoring in a production build. Adapt the checklist to the Next.js version and deployment environment you use.

Architecture and Component Model

  • Server components are the default. Keep rendering and data access on the server where the component composition allows it. Place use client at the smallest practical interactive boundary.
  • use client boundaries match the interaction. Keep unrelated content outside the client module graph; state, context providers, and component composition may require a boundary above an individual control.
  • Server-only code is enforced. Import server-only in any module that accesses secrets, the database, or the filesystem to prevent accidental client-side exposure.
  • No secrets are passed as props to client components. Only sanitized, presentation-safe data crosses the server-to-client boundary.

Data Fetching

  • Parallel fetches use Promise.all. Independent await calls in the same component are grouped so their latencies do not stack.
  • Slow data sources are wrapped in Suspense. Users see partial content immediately; slower sections stream in without blocking initial HTML.
  • Dynamic routes have an intentional rendering strategy. Use generateStaticParams for routes you want to pre-render; request-time rendering is appropriate for other routes.
  • Database queries use connection pooling. Serverless environments open many connections. A pooler like PgBouncer or a serverless-optimized client prevents exhausting the connection limit.

Caching

  • Each data source has an explicit cache policy. No fetch call relies on the default behavior without the team understanding what that default is.
  • Cache invalidation is wired to mutations. Choose the supported revalidation behavior for your Next.js version. Stale-while-revalidate and immediate read-after-write freshness require different handling.
  • cache: 'no-store' is used sparingly and intentionally. Disabling caching on a fetch that does not change per-request is waste; confirm the reason before opting out.
  • Sensitive personalized data is not cached. Cache keys that could collide across users do not cache user-specific responses.

Routing and Navigation

  • Route groups organize shared layouts. Folders wrapped in parentheses group related routes under a shared layout without polluting the URL.
  • not-found.tsx and error.tsx exist at appropriate levels. Place boundaries where users need a distinct recovery experience; child segments can use an ancestor boundary.
  • loading.tsx shows meaningful skeletons. Loading states match the shape of the content that replaces them, reducing layout shift.
  • Middleware matchers exclude static assets. The middleware matcher pattern does not run auth or analytics logic on /_next/static/, /favicon.ico, or image files.

Security

  • All form mutations have server-side validation and authorization. Apply these checks in Server Actions, Route Handlers, or whichever server endpoint performs the mutation.
  • Rate limiting is applied to sensitive endpoints. Login forms, signup flows, and mutation endpoints have rate limits enforced at the middleware or edge layer.
  • Content-Security-Policy headers are configured. Next.js supports setting security headers in next.config.js under headers. CSP, X-Frame-Options, and Referrer-Policy are set.
  • Environment variables are audited. Variables prefixed with NEXT_PUBLIC_ are visible in the browser. Secrets use unprefixed names and are never exposed to the client.

Performance

  • Images have appropriate delivery and loading policies. Use next/image where it fits, size images for their display context, and avoid lazy-loading the likely LCP image.
  • Font loading is tested. Consider next/font for self-hosting and fallback metrics, and measure layout shift with the actual fonts and styles.
  • Bundle analyzer has been run. @next/bundle-analyzer is used at least once before launch to identify unexpectedly large client-side dependencies.
  • Core Web Vitals are measured before launch. Check LCP and CLS in production-like lab tests, then use field monitoring to measure real-user INP and the other Core Web Vitals. Known regressions are addressed before users see them.

Observability

  • Structured logging is in place. Application errors and key events write to a log aggregation service, not just console.log.
  • Error tracking captures server-side exceptions. A tool like Sentry is configured to capture both server component errors and client-side exceptions.
  • Uptime monitoring covers key routes. A synthetic monitor pings key routes and alerts when response times degrade or status codes change.