Why a Checklist Matters
Every time I've launched a Next.js application without a checklist, something got missed. Maybe it was security headers, or image optimization, or proper error handling, or cache configuration. Individually, none of these are hard. Collectively, they're easy to forget under launch pressure.
This checklist is the distillation of six production launches. Not everything applies to every project, but reviewing each item takes minutes and catching a missed item saves hours of post-launch firefighting.
Performance
Image Optimization
Use Next.js Image component for all images. It handles lazy loading, responsive sizing, and format conversion (WebP, AVIF) automatically. The most common mistake is using plain img tags "just for now" and never going back. Configure image domains in next.config and set appropriate quality values — 75 is a good default for photos, 90+ for sharp graphics.
Font Optimization
Use next/font for web fonts. It eliminates layout shift by preloading fonts and using font-display: swap. Self-hosting fonts through next/font is faster than Google Fonts CDN for most deployments because it eliminates the DNS lookup and connection to fonts.googleapis.com.
Bundle Analysis
Run your build with bundle analysis enabled before launch. Look for unexpectedly large dependencies, duplicate packages, and code that should be dynamically imported. A single unoptimized import can add hundreds of KB to your bundle.
Common offenders: moment.js (use date-fns or dayjs instead), lodash (import individual functions, not the whole library), and icon libraries (import specific icons, not the entire set).
Core Web Vitals
Measure Largest Contentful Paint (LCP), First Input Delay (FID), and Cumulative Layout Shift (CLS) using Lighthouse and real user monitoring. Google uses these metrics for search ranking, and users feel them directly.
LCP above 2.5 seconds: check your largest above-the-fold image or text block. Are you using next/image? Is the font loading efficiently? FID above 100ms: check for heavy JavaScript execution on page load. CLS above 0.1: check for elements that load without dimensions (images, ads, dynamic content).
Static Generation Where Possible
Use static generation (SSG) for pages that don't change per-request: marketing pages, blog posts, documentation. These pages are served from a CDN with zero server-side computation. Use Incremental Static Regeneration (ISR) for pages that change occasionally but don't need to be fresh on every request.
Reserve server-side rendering (SSR) for pages that must reflect real-time data: user dashboards, shopping carts, personalized content.
Security
HTTP Security Headers
Configure security headers in your middleware or next.config: Content-Security-Policy (prevents XSS and injection attacks), X-Frame-Options (prevents clickjacking), X-Content-Type-Options (prevents MIME sniffing), Referrer-Policy (controls referrer information), and Strict-Transport-Security (enforces HTTPS).
Content-Security-Policy is the most complex and most important. Start with a restrictive policy and loosen it as needed. Report-only mode lets you test without breaking your site.
Environment Variables
Never expose server-side secrets to the client. In Next.js, only variables prefixed with NEXT_PUBLIC_ are bundled into client-side code. Audit your environment variables to ensure database credentials, API secrets, and internal URLs aren't accidentally prefixed.
Store secrets in your deployment platform's secret management (Vercel Environment Variables, AWS Secrets Manager, etc.), not in .env files committed to your repository.
Authentication and Authorization
Implement authentication on every protected route, not just the page level. API routes, server actions, and middleware should all verify the user's identity and permissions. A common vulnerability is protecting the UI but leaving API routes open.
Use httpOnly, secure, sameSite cookies for session tokens. Never store tokens in localStorage — it's vulnerable to XSS attacks.
Rate Limiting
Protect your API routes from abuse. Implement rate limiting based on authenticated user ID (for logged-in users) or IP address (for public endpoints). Return 429 Too Many Requests with a Retry-After header.
SEO
Metadata
Use Next.js Metadata API to set title, description, and Open Graph tags on every page. Each page should have a unique, descriptive title and a compelling description. Open Graph images improve click-through rates from social media.
Sitemap and Robots
Generate a dynamic sitemap at /sitemap.xml that includes all public pages with appropriate priority and changefreq values. Create a robots.txt that allows search engine crawling of public pages and blocks private areas.
Structured Data
Add JSON-LD structured data for your content type: Article for blog posts, Product for e-commerce, Organization for your company page, BreadcrumbList for navigation. Google uses structured data for rich snippets in search results.
Canonical URLs
Set canonical URLs on every page to prevent duplicate content issues. This is especially important if your content is accessible at multiple URLs (with and without trailing slashes, with query parameters, etc.).
Error Handling
Error Boundaries
Create custom error.tsx and not-found.tsx pages at the app level and for critical route segments. A production application should never show the default Next.js error page — it exposes your tech stack and looks unprofessional.
Error Tracking
Integrate an error tracking service (Sentry, Bugsnag, or similar) that captures both client-side and server-side errors. Configure source maps so you can debug minified production errors with original file names and line numbers.
Graceful Degradation
Plan for external service failures. If your CMS is down, can your site still render cached content? If your payment provider is slow, does the checkout show a helpful message instead of hanging? Each external dependency should have a fallback strategy.
Operational Readiness
Health Check Endpoint
Create an API route that verifies your application can connect to its dependencies (database, cache, external APIs). Monitoring systems and load balancers use this to determine if an instance is healthy.
Logging
Implement structured logging (JSON format) with request IDs for traceability. Log at appropriate levels: errors for failures, warnings for degraded behavior, info for significant events. Don't log sensitive data (passwords, tokens, personal information).
Environment Parity
Your development, staging, and production environments should be as similar as possible. Use the same Node.js version, the same build process, and similar infrastructure. Differences between environments are a leading source of "works on staging, breaks in production" incidents.
Deployment Strategy
Configure zero-downtime deployments with health check verification. Your deployment platform should start new instances, verify they're healthy, route traffic to them, and then stop old instances. A deploy should never cause user-facing errors.
Backup and Recovery
For applications with data persistence, ensure regular backups and test the recovery process. A backup you've never restored is a hope, not a plan. Run a recovery drill at least quarterly.
Pre-Launch Final Checks
Before clicking deploy on launch day: test every page on mobile and desktop, verify all forms submit correctly, check that error pages render properly, confirm analytics and monitoring are receiving data, verify SSL certificates are valid and auto-renewing, test the deployment rollback process, and ensure someone is available to monitor for the first few hours after launch.
This checklist won't prevent every production issue, but it eliminates the preventable ones — which is most of them.