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 clientat the smallest practical interactive boundary. use clientboundaries 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-onlyin 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. Independentawaitcalls 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
generateStaticParamsfor 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.tsxanderror.tsxexist at appropriate levels. Place boundaries where users need a distinct recovery experience; child segments can use an ancestor boundary.loading.tsxshows 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-Policyheaders are configured. Next.js supports setting security headers innext.config.jsunderheaders. CSP,X-Frame-Options, andReferrer-Policyare 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/imagewhere it fits, size images for their display context, and avoid lazy-loading the likely LCP image. - Font loading is tested. Consider
next/fontfor self-hosting and fallback metrics, and measure layout shift with the actual fonts and styles. - Bundle analyzer has been run.
@next/bundle-analyzeris 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.