Vercel vs Netlify vs Cloudflare Pages: Deployment Platforms (2026)
TL;DR
Vercel is the platform built for Next.js — zero-config deployment, edge/serverless functions, image optimization, analytics, the gold standard for React/Next.js apps. Netlify is the Jamstack platform — git-connected deploys, serverless functions, edge functions, forms, identity, split testing, framework-agnostic. Cloudflare Pages is the edge-first platform — global edge deployment, Workers integration, zero cold starts, generous free tier, built on Cloudflare's network. In 2026: Vercel for Next.js and React frameworks, Netlify for Jamstack and static sites, Cloudflare Pages for edge-first applications.
Key Takeaways
- Vercel: Best for Next.js — automatic optimization, ISR, RSC, middleware
- Netlify: Best for Jamstack — framework-agnostic, built-in forms/identity
- Cloudflare Pages: Best value — generous free tier, zero cold starts, Workers
- All three deploy from git with preview deployments
- Vercel has the tightest Next.js integration (they created Next.js)
- Cloudflare Pages has the most generous free tier
Vercel
Vercel — platform for frontend frameworks:
Deploy Next.js
# Connect repo and deploy:
npx vercel
# Or via git push (auto-deploy):
# 1. Connect GitHub repo in Vercel dashboard
# 2. Push to main → production deploy
# 3. Push to branch → preview deploy
vercel.json configuration
{
"framework": "nextjs",
"buildCommand": "next build",
"outputDirectory": ".next",
"regions": ["iad1", "sfo1"],
"env": {
"DATABASE_URL": "@database-url"
},
"headers": [
{
"source": "/api/(.*)",
"headers": [
{ "key": "Access-Control-Allow-Origin", "value": "*" }
]
}
],
"redirects": [
{ "source": "/old-blog/:slug", "destination": "/blog/:slug", "permanent": true }
],
"rewrites": [
{ "source": "/api/:path*", "destination": "https://api.pkgpulse.com/:path*" }
]
}
Serverless functions
// api/packages/[name].ts
import type { VercelRequest, VercelResponse } from "@vercel/node"
export default async function handler(
req: VercelRequest,
res: VercelResponse
) {
const { name } = req.query
const data = await fetch(`https://registry.npmjs.org/${name}`)
const pkg = await data.json()
res.setHeader("Cache-Control", "s-maxage=3600, stale-while-revalidate")
res.json({
name: pkg.name,
version: pkg["dist-tags"].latest,
description: pkg.description,
})
}
Edge functions
// middleware.ts (Next.js middleware runs on Vercel Edge):
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
export function middleware(request: NextRequest) {
// Geo-based routing:
const country = request.geo?.country || "US"
if (country === "DE") {
return NextResponse.rewrite(new URL("/de" + request.nextUrl.pathname, request.url))
}
// A/B testing:
const bucket = request.cookies.get("ab-bucket")?.value || (Math.random() < 0.5 ? "a" : "b")
const response = NextResponse.next()
response.cookies.set("ab-bucket", bucket)
response.headers.set("x-ab-bucket", bucket)
return response
}
export const config = { matcher: ["/((?!_next|api|favicon).*)"] }
Key features
Vercel highlights:
✅ Zero-config Next.js deployment
✅ Automatic HTTPS and CDN
✅ Preview deployments per branch/PR
✅ Edge Middleware (global, zero cold start)
✅ Serverless Functions (Node.js, Go, Python, Ruby)
✅ Image Optimization (next/image)
✅ ISR (Incremental Static Regeneration)
✅ Analytics and Speed Insights
✅ Vercel KV, Postgres, Blob storage
✅ Domain management
Netlify
Netlify — Jamstack platform:
Deploy
# CLI deploy:
npx netlify deploy --prod
# Or connect GitHub for auto-deploy
# netlify.toml for configuration:
netlify.toml configuration
[build]
command = "npm run build"
publish = "dist"
[build.environment]
NODE_VERSION = "20"
# Redirects:
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
[[redirects]]
from = "/old-blog/*"
to = "/blog/:splat"
status = 301
# Headers:
[[headers]]
for = "/api/*"
[headers.values]
Access-Control-Allow-Origin = "*"
Cache-Control = "public, max-age=3600"
# Functions:
[functions]
directory = "netlify/functions"
node_bundler = "esbuild"
Serverless functions
// netlify/functions/packages.ts
import type { Handler, HandlerEvent } from "@netlify/functions"
export const handler: Handler = async (event: HandlerEvent) => {
const name = event.queryStringParameters?.name
if (!name) {
return { statusCode: 400, body: JSON.stringify({ error: "Name required" }) }
}
const data = await fetch(`https://registry.npmjs.org/${name}`)
const pkg = await data.json()
return {
statusCode: 200,
headers: {
"Content-Type": "application/json",
"Cache-Control": "public, max-age=3600",
},
body: JSON.stringify({
name: pkg.name,
version: pkg["dist-tags"].latest,
}),
}
}
Edge functions
// netlify/edge-functions/geolocation.ts
import type { Context } from "@netlify/edge-functions"
export default async function handler(request: Request, context: Context) {
const country = context.geo.country?.code || "US"
// Geo-based content:
if (country === "DE") {
const url = new URL(request.url)
url.pathname = "/de" + url.pathname
return context.rewrite(url)
}
return context.next()
}
export const config = { path: "/*" }
Built-in features
Netlify highlights:
✅ Git-connected deploys (auto PR previews)
✅ Netlify Forms (no backend needed)
✅ Netlify Identity (auth without code)
✅ Split Testing (A/B by branch)
✅ Edge Functions (Deno-based)
✅ Serverless Functions (Node.js)
✅ Build plugins ecosystem
✅ Large Media (Git LFS)
✅ Analytics
✅ Framework-agnostic (Astro, SvelteKit, Next.js, etc.)
Cloudflare Pages
Cloudflare Pages — edge-first platform:
Deploy
# CLI deploy:
npx wrangler pages deploy ./dist
# Or connect GitHub for auto-deploy
# wrangler.toml for configuration:
wrangler.toml configuration
name = "pkgpulse"
compatibility_date = "2026-03-09"
pages_build_output_dir = "./dist"
# Bindings (access Cloudflare services):
[[kv_namespaces]]
binding = "CACHE"
id = "abc123..."
[[d1_databases]]
binding = "DB"
database_name = "pkgpulse"
database_id = "def456..."
[[r2_buckets]]
binding = "ASSETS"
bucket_name = "pkgpulse-assets"
[vars]
ENVIRONMENT = "production"
Functions (file-based routing)
// functions/api/packages/[name].ts
interface Env {
DB: D1Database
CACHE: KVNamespace
}
export const onRequestGet: PagesFunction<Env> = async (context) => {
const name = context.params.name as string
// Check cache:
const cached = await context.env.CACHE.get(`pkg:${name}`)
if (cached) {
return new Response(cached, {
headers: { "Content-Type": "application/json" },
})
}
// Fetch from registry:
const data = await fetch(`https://registry.npmjs.org/${name}`)
const pkg = await data.json()
const result = JSON.stringify({
name: pkg.name,
version: pkg["dist-tags"].latest,
})
// Cache for 1 hour:
await context.env.CACHE.put(`pkg:${name}`, result, { expirationTtl: 3600 })
return new Response(result, {
headers: { "Content-Type": "application/json" },
})
}
Full-stack with D1 and R2
// functions/api/reports.ts
interface Env {
DB: D1Database
ASSETS: R2Bucket
}
export const onRequestPost: PagesFunction<Env> = async (context) => {
const body = await context.request.json()
// Write to D1 (SQLite at the edge):
await context.env.DB.prepare(
"INSERT INTO reports (name, data, created_at) VALUES (?, ?, ?)"
).bind(body.name, JSON.stringify(body.data), new Date().toISOString()).run()
// Store file in R2:
await context.env.ASSETS.put(
`reports/${body.name}.json`,
JSON.stringify(body.data),
{ httpMetadata: { contentType: "application/json" } }
)
return new Response(JSON.stringify({ success: true }), {
headers: { "Content-Type": "application/json" },
})
}
Key features
Cloudflare Pages highlights:
✅ Global edge deployment (300+ locations)
✅ Zero cold starts (V8 isolates, not containers)
✅ Generous free tier (unlimited sites, 500 builds/month)
✅ Workers integration (full Cloudflare platform)
✅ D1 (edge SQLite), R2 (object storage), KV
✅ Preview deployments per branch
✅ Custom domains and automatic HTTPS
✅ Framework support (Next.js, Astro, SvelteKit, Remix)
✅ Web Analytics (free, privacy-first)
✅ DDoS protection included
Feature Comparison
| Feature | Vercel | Netlify | Cloudflare Pages |
|---|---|---|---|
| Best for | Next.js | Jamstack | Edge-first apps |
| Framework support | All (Next.js best) | All | All |
| Edge functions | ✅ (Middleware) | ✅ (Deno-based) | ✅ (Workers) |
| Serverless functions | ✅ | ✅ | ✅ (file-based) |
| Cold starts | ~250ms | ~250ms | ~0ms (V8 isolates) |
| Global CDN | ✅ | ✅ | ✅ (300+ PoPs) |
| Preview deploys | ✅ | ✅ | ✅ |
| Built-in DB | Vercel Postgres, KV | ❌ | D1, KV |
| Object storage | Vercel Blob | ❌ | R2 |
| Forms | ❌ | ✅ (built-in) | ❌ |
| Identity/auth | ❌ | ✅ (built-in) | ❌ |
| Image optimization | ✅ (next/image) | ✅ (Netlify Image CDN) | ✅ (Images) |
| Analytics | ✅ (paid) | ✅ (paid) | ✅ (free) |
| DDoS protection | ✅ | ✅ | ✅ (Cloudflare) |
| Free tier | 100GB bandwidth | 100GB bandwidth | Unlimited bandwidth |
| Pricing | Per-seat + usage | Per-seat + usage | Usage-based |
When to Use Each
Use Vercel if:
- Building with Next.js (best-in-class support)
- Want zero-config deployment with automatic optimizations
- Need ISR, RSC, and advanced Next.js features
- Want integrated Postgres, KV, and Blob storage
Use Netlify if:
- Building Jamstack or static sites with any framework
- Want built-in forms and identity (no backend needed)
- Need split testing by branch (A/B testing)
- Prefer a framework-agnostic platform
Use Cloudflare Pages if:
- Want zero cold starts and true edge computing
- Need the most generous free tier (unlimited bandwidth)
- Want D1 (edge SQLite) and R2 (object storage)
- Building on the Cloudflare ecosystem (Workers, KV, Queues)
Methodology
Feature comparison based on Vercel, Netlify, and Cloudflare Pages platforms and pricing as of March 2026.