Next.js 15 Production Checklist

August 13, 2025 (10d ago)

8 min read

...

Next.js 15 introduces significant changes that impact production deployments. With Turbopack approaching stability, new caching defaults, and enhanced App Router features, here's your comprehensive checklist for shipping production-ready applications in 2025.

App Router & Architecture

Complete Migration Strategy

// next.config.ts - New TypeScript support in Next.js 15 import { NextConfig } from 'next' const config: NextConfig = { experimental: { // Turbopack for dev (stable in 15) turbo: { // Configure Turbopack if needed }, // Cache Components (beta in 16, experimental in 15) cacheComponents: true, }, // TypeScript support for config files typescript: { // Type-safe configurations with autocompletion ignoreBuildErrors: false, }, } export default config

Migration Checklist:

  • ✅ Fully migrate to App Router (avoid Pages Router mixing)
  • ✅ Convert all pages/api routes to app/api Route Handlers
  • ✅ Use Server Components as default, minimize "use client" directives
  • ✅ Implement proper loading.tsx and error.tsx boundaries
  • ✅ Leverage the new Static Route Indicator during development

Data Fetching & Caching

Next.js 15 changed caching defaults significantly. Understanding these changes is crucial for production performance.

// NEW: Explicit caching required in Next.js 15 async function getUser(id: string) { // No longer cached by default - must opt-in const response = await fetch(`/api/users/${id}`, { cache: 'force-cache', // Opt into caching next: { revalidate: 3600 } // Revalidate every hour }) return response.json() } // Route handlers are also uncached by default export async function GET() { const data = await fetchData() return Response.json(data, { headers: { 'Cache-Control': 's-maxage=3600, stale-while-revalidate=86400' } }) }

Caching Strategy Checklist:

  • ✅ Audit all fetch calls - add explicit caching where needed
  • ✅ Configure Route Handler caching manually
  • ✅ Use revalidatePath() and revalidateTag() for targeted invalidation
  • ✅ Implement proper ISR with revalidate configuration
  • ✅ Monitor cache hit rates in production

Performance Optimization

Core Web Vitals Implementation

// components/PerformanceOptimized.tsx import { Image } from 'next/image' import { Suspense } from 'react' export function OptimizedLanding() { return ( <main> {/* LCP optimization with priority loading */} <Image src="/hero-image.jpg" alt="Hero image" width={1200} height={600} priority // Critical for LCP placeholder="blur" blurDataURL="data:image/jpeg;base64,..." /> {/* Lazy load below-fold content */} <Suspense fallback={<LoadingSkeleton />}> <BelowFoldContent /> </Suspense> </main> ) }

Turbopack Integration (2025 Status)

# Development (Stable in Next.js 15) npm run dev --turbo # Production build (Alpha in 15, Beta in 16) npm run build --turbo # Use cautiously in production

Turbopack Benefits:

  • 76.7% faster local server startup for large apps
  • 96.3% faster code updates with Fast Refresh
  • 45.8% faster initial route compilation
  • 30% reduction in memory usage during development

Performance Checklist:

  • ✅ Enable Turbopack for development workflows
  • ✅ Test next build --turbopack in staging (alpha quality)
  • ✅ Implement proper image optimization with next/image
  • ✅ Add preloading for critical routes and fonts
  • ✅ Use dynamic imports for code splitting: dynamic(() => import('./Component'))
  • ✅ Monitor Core Web Vitals with Real User Monitoring (RUM)

Security Hardening

Comprehensive Security Headers

// middleware.ts - Production security headers import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' export function middleware(request: NextRequest) { const response = NextResponse.next() // Security headers for production response.headers.set('X-DNS-Prefetch-Control', 'on') response.headers.set('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload') response.headers.set('X-Frame-Options', 'SAMEORIGIN') response.headers.set('X-Content-Type-Options', 'nosniff') response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin') response.headers.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=()') // CSP for XSS protection response.headers.set( 'Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" ) return response }

Server Actions Security

// app/actions.ts - Secure server actions import { z } from 'zod' import { revalidatePath } from 'next/cache' const CreateUserSchema = z.object({ email: z.string().email(), name: z.string().min(1).max(100), }) export async function createUser(formData: FormData) { // Always validate input server-side const validatedFields = CreateUserSchema.safeParse({ email: formData.get('email'), name: formData.get('name'), }) if (!validatedFields.success) { return { error: 'Invalid input data' } } // Verify user authorization const session = await getSession() if (!session?.user) { return { error: 'Unauthorized' } } try { await createUserInDB(validatedFields.data) revalidatePath('/users') return { success: true } } catch (error) { return { error: 'Failed to create user' } } }

Security Checklist:

  • ✅ Implement robust Content Security Policy (CSP)
  • ✅ Enable all security headers via middleware or hosting platform
  • ✅ Validate all Server Action inputs with libraries like Zod
  • ✅ Use server-only package for sensitive server code
  • ✅ Keep dependencies updated with automated security scanning
  • ✅ Sanitize any user-generated content (MDX/HTML)
  • ✅ Implement proper authentication and authorization flows

Observability & Monitoring

Comprehensive Error Tracking

// lib/monitoring.ts - Production monitoring setup import { withSentry } from '@sentry/nextjs' // Error boundary for client components export function GlobalErrorBoundary({ children }: { children: React.ReactNode }) { return ( <ErrorBoundary fallback={<ErrorFallback />} onError={(error, errorInfo) => { console.error('Error caught by boundary:', error, errorInfo) // Send to monitoring service Sentry.captureException(error, { extra: errorInfo }) }} > {children} </ErrorBoundary> ) } // Server action error handling export async function monitoredServerAction(formData: FormData) { try { const result = await performAction(formData) return result } catch (error) { // Log server-side errors console.error('Server action failed:', error) Sentry.captureException(error) return { error: 'Action failed' } } }

OpenTelemetry Integration

// instrumentation.ts - Next.js 15 built-in instrumentation export async function register() { if (process.env.NEXT_RUNTIME === 'nodejs') { const { NodeSDK } = await import('@opentelemetry/sdk-node') const { getNodeAutoInstrumentations } = await import('@opentelemetry/auto-instrumentations-node') const sdk = new NodeSDK({ instrumentations: [getNodeAutoInstrumentations()], }) sdk.start() } }

Monitoring Checklist:

  • ✅ Set up error reporting (Sentry, Bugsnag)
  • ✅ Implement distributed tracing with OpenTelemetry
  • ✅ Monitor Core Web Vitals in production
  • ✅ Track API response times and error rates
  • ✅ Set up alerts for performance degradation
  • ✅ Monitor server action performance and errors
  • ✅ Use Next.js Speed Insights for real-user data

SEO & Metadata Enhancement

Complete Metadata Setup

// app/layout.tsx - Enhanced metadata import type { Metadata } from 'next' export const metadata: Metadata = { title: { template: '%s | Your App', default: 'Your App - Description', }, description: 'Comprehensive description for SEO', keywords: ['keyword1', 'keyword2'], authors: [{ name: 'Your Name' }], creator: 'Your Company', publisher: 'Your Company', formatDetection: { email: false, address: false, telephone: false, }, openGraph: { type: 'website', locale: 'en_US', url: 'https://yourapp.com', siteName: 'Your App', images: [ { url: 'https://yourapp.com/og-image.jpg', width: 1200, height: 630, alt: 'Your App', }, ], }, twitter: { card: 'summary_large_image', title: 'Your App', description: 'Description for Twitter', images: ['https://yourapp.com/twitter-image.jpg'], }, robots: { index: true, follow: true, googleBot: { index: true, follow: true, 'max-video-preview': -1, 'max-image-preview': 'large', 'max-snippet': -1, }, }, }

Dynamic Sitemap Generation

// app/sitemap.ts - Dynamic sitemap import type { MetadataRoute } from 'next' export default async function sitemap(): Promise<MetadataRoute.Sitemap> { const baseUrl = 'https://yourapp.com' // Static pages const staticPages = [ '', '/about', '/contact', ].map(route => ({ url: `${baseUrl}${route}`, lastModified: new Date().toISOString(), changeFrequency: 'monthly' as const, priority: route === '' ? 1 : 0.8, })) // Dynamic pages from database const posts = await getPosts() const dynamicPages = posts.map(post => ({ url: `${baseUrl}/blog/${post.slug}`, lastModified: post.updatedAt, changeFrequency: 'weekly' as const, priority: 0.6, })) return [...staticPages, ...dynamicPages] }

CI/CD & Deployment Pipeline

Comprehensive GitHub Actions Workflow

# .github/workflows/production.yml name: Production Deploy on: push: branches: [main] jobs: test-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: Type check run: npm run type-check - name: Lint run: npm run lint - name: Run tests run: npm run test - name: Build application run: npm run build env: NODE_ENV: production - name: Run E2E tests run: npm run test:e2e - name: Security audit run: npm audit --audit-level high - name: Deploy to production if: success() run: npm run deploy env: DEPLOYMENT_TOKEN: ${{ secrets.DEPLOYMENT_TOKEN }}

Environment Configuration

// lib/env.ts - Type-safe environment variables import { z } from 'zod' const envSchema = z.object({ NODE_ENV: z.enum(['development', 'test', 'production']), DATABASE_URL: z.string().url(), NEXTAUTH_SECRET: z.string().min(32), NEXTAUTH_URL: z.string().url(), NEXT_PUBLIC_APP_URL: z.string().url(), }) export const env = envSchema.parse(process.env)

CI/CD Checklist:

  • ✅ Implement comprehensive testing pipeline (unit, integration, E2E)
  • ✅ Add TypeScript strict checking in CI
  • ✅ Use ESLint with Next.js recommended rules
  • ✅ Run security audits on dependencies
  • ✅ Implement visual regression testing
  • ✅ Use preview deployments for feature branches
  • ✅ Add performance budgets and monitoring
  • ✅ Implement automated rollback on deployment failures

Production Deployment Considerations

Database & Infrastructure

  • ✅ Ensure database and backend are in the same region as your app
  • ✅ Implement proper database connection pooling
  • ✅ Use caching layers (Redis) for session storage and frequently accessed data
  • ✅ Configure CDN for static assets

Hosting Platform Optimization

  • ✅ Configure proper Edge Functions for API routes requiring low latency
  • ✅ Set up proper logging and log retention policies
  • ✅ Implement health checks and uptime monitoring
  • ✅ Configure auto-scaling based on traffic patterns

Performance Benchmarks for 2025

Recent metrics from production Next.js 15 applications show:

  • 57.6% faster compile times with Turbopack (development)
  • 30% reduction in memory usage during local development
  • 20-40% improvement in Time to First Byte (TTFB) with proper Server Components usage
  • 15-25% reduction in bundle sizes with enhanced tree-shaking

Quick Production Health Check

Use this final checklist before going live:

  1. ✅ Performance: Lighthouse score >90, Core Web Vitals in green
  2. ✅ Security: All security headers configured, dependencies updated
  3. ✅ SEO: Proper metadata, sitemap, robots.txt configured
  4. ✅ Monitoring: Error tracking, performance monitoring, alerts set up
  5. ✅ Caching: Explicit caching strategy implemented for Next.js 15
  6. ✅ CI/CD: Automated testing, type checking, security audits
  7. ✅ Backup: Database backups, deployment rollback strategy

Next.js 15 represents a significant evolution in the framework. The key to success is understanding the new caching defaults, leveraging Turbopack for development productivity, and implementing comprehensive monitoring. Start with this checklist and iterate based on your specific application needs and traffic patterns.

Loading reactions...
Similar Posts

Here are some other articles you might find interesting.

Subscribe to my newsletter

A periodic update about my life, recent blog posts, how-tos, and discoveries.

NO SPAM. I never send spam. You can unsubscribe at any time!

Srivathsav's Logo

I'm Srivathsav - an AI/ML and software engineer passionate about building intelligent systems and sharing ideas. Thanks for stopping by!

© 2025 Jaya Raj Srivathsav Adari