Deploying a Next.js application is easy. Deploying it at scale, with reliability and performance? That requires more thought. Here's what I've learned running Next.js in production.
Choosing Your Platform
Vercel
The path of least resistance. Vercel is built by the Next.js team, so you get first-class support for every feature. Edge Functions, ISR, Image Optimization — it all just works.
Best for: Teams that want to ship fast without managing infrastructure.
Self-Hosted with Docker
For teams that need more control or have compliance requirements:
FROM node:22-alpine AS base
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]Kubernetes
For large-scale deployments, Kubernetes gives you auto-scaling, rolling deployments, and self-healing:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nextjs-app
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0Caching Strategy
Static Assets
Set long cache headers for static assets. Next.js already hashes filenames, so you can cache aggressively:
Cache-Control: public, max-age=31536000, immutableISR (Incremental Static Regeneration)
ISR lets you update static pages without rebuilding the entire site. Set revalidation periods based on how frequently your content changes:
export const revalidate = 3600; // Revalidate every hourCDN Configuration
Put a CDN in front of your application. Cloudflare or AWS CloudFront work well. Configure cache rules to cache static pages while bypassing dynamic routes.
Monitoring and Observability
Health Checks
Always implement a health check endpoint:
export async function GET() {
const dbHealthy = await checkDatabase();
const status = dbHealthy ? 200 : 503;
return Response.json({ status: dbHealthy ? 'healthy' : 'unhealthy' }, { status });
}Error Tracking
Use Sentry or a similar service to catch errors in production. Next.js has excellent Sentry integration.
Performance Monitoring
Track Core Web Vitals in production. Vercel Analytics does this automatically, or you can use the web-vitals library to send metrics to your own analytics service.
Database Connections
In serverless environments, database connections can be tricky. Use connection pooling:
- PostgreSQL: Use PgBouncer or Neon's built-in pooling
- MongoDB: Use MongoDB Atlas with connection pooling enabled
- Prisma: Configure the connection pool size in your schema
Conclusion
Deploying Next.js at scale requires thinking about caching, monitoring, and infrastructure from the start. Whether you choose Vercel or self-host, the key is to have a solid deployment pipeline, proper caching, and comprehensive monitoring.