Where you deploy affects performance, cost, and complexity. Vercel offers polish, Cloudflare brings edge power, and self-hosting gives control. Here's how to choose.
Vercel: The Next.js Native Option
Pros:
- Zero-config Next.js deployment
- Excellent preview deployments
- Built-in analytics and observability
- Team collaboration features
Cons:
- Premium pricing at scale
- Function duration limits
- Vendor lock-in concerns
// vercel.json
{
"functions": {
"app/api/**": {
"maxDuration": 60 // Pro plan required for >10s
}
},
"regions": ["iad1", "sfo1", "cdg1"] // Deploy to multiple regions
}
Cloudflare Pages: Edge-First
Pros:
- Generous free tier
- True edge deployment globally
- Integrated with Workers, KV, D1
- Excellent performance
Cons:
- Next.js support via adapter (not native)
- Some features require adaptation
- Smaller ecosystem
// next.config.js for Cloudflare
module.exports = {
experimental: {
runtime: 'edge',
},
}
// Deploy
// npx @cloudflare/next-on-pages
// wrangler pages deploy .vercel/output/static
Self-Hosting: Docker and Kubernetes
Pros:
- Complete control
- No vendor lock-in
- Can be cheapest at scale
- Custom infrastructure possible
Cons:
- Operational overhead
- You handle scaling, security, uptime
- Slower iteration
# Dockerfile for Next.js
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine 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"]
Cost Comparison at Scale
const monthlyEstimates = {
// 1M page views, 100K function invocations
vercel: {
pro: 20,
bandwidth: 0, // Included
functions: 0, // Included up to limit
analytics: 0, // Basic included
total: 20,
// At higher scale: $150-500+
},
cloudflare: {
pages: 0, // Free tier
workers: 5, // Paid Workers
bandwidth: 0, // Free
total: 5,
// At higher scale: $25-100
},
selfHosted: {
server: 50, // VPS or cloud VM
bandwidth: 20, // Varies by provider
monitoring: 20, // Datadog, etc.
time: 'priceless', // Your time
total: 90,
// At higher scale: $200-2000 but more predictable
},
}
Migration Strategies
// Vercel → Self-hosted
// 1. Ensure standalone output
module.exports = {
output: 'standalone',
}
// 2. Build Docker image
// 3. Set up infrastructure (K8s, Docker Compose)
// 4. Configure CDN for static assets
// 5. Set up monitoring
// 6. Gradual traffic migration
// Self-hosted → Vercel
// 1. Remove custom server code
// 2. Migrate env vars to Vercel
// 3. Ensure API routes fit function limits
// 4. Set up Vercel project
// 5. Connect domain
// 6. Done (much simpler!)
Decision Matrix
function recommendPlatform(requirements) {
if (requirements.team.size < 5 && requirements.budget === 'startup') {
return 'Cloudflare Pages' // Best value
}
if (requirements.nextjs && requirements.prioritize === 'DX') {
return 'Vercel' // Best experience
}
if (requirements.scale === 'large' && requirements.team.hasDevOps) {
return 'Self-hosted' // Best economics at scale
}
if (requirements.compliance === 'strict') {
return 'Self-hosted' // Best control
}
return 'Vercel' // Safe default
}
Key Takeaways
Vercel: Best DX, premium pricing, ideal for teams prioritizing velocity.
Cloudflare: Best value, edge-first, requires some adaptation.
Self-hosted: Best control, most work, cheapest at very large scale.
