Vercel vs Cloudflare (Workers + Pages) Comparison

The source of Next.js — ship the newest features with zero configuration

VS
Cloudflare (Workers + Pages)

A global V8-isolate network — zero egress, now with its own Next.js layer, vinext

15 min readDevOps

Quick Verdict

It depends on your situation. If you want the newest Next.js features with zero lag, choose Vercel — there's no parity risk. If you're running a bandwidth-heavy, global project and prioritize predictable cost, Cloudflare is the right bet; alongside the mature OpenNext, there's now the beta but fast-moving vinext. For critical work, start with OpenNext; try vinext on a new project.

VercelCloudflare (Workers + Pages)
Read the full verdict

Score Comparison

Loading chart...

Detailed Scoring

Detailed Scoring: Vercel and Cloudflare (Workers + Pages) — category-by-category scores out of 10
CategoryVercelCloudflare (Workers + Pages)
Performance
8/10
9/10
Ease of Learning
9/10
6/10
Ecosystem
9/10
7/10
Community
9/10
8/10
Job Market
8/10
7/10
Future-Proof
8/10
8/10

Pros & Cons

Vercel

Pros

  • Since Vercel builds Next.js, new features (PPR, Turbopack, App Router) mature here first
  • Zero-config deploy — just git push; build/ISR/edge middleware are configured automatically
  • 126 PoPs / 51 countries of CDN plus 20 compute-capable regions for low-latency SSR
  • Fluid Compute bills Active CPU only — billing pauses during pending I/O
  • Preview deployments are automatic for every PR, fitting naturally into team workflows
  • Official Next.js Cache APIs (revalidateTag, revalidatePath) are supported first-hand

Cons

  • Fast Data Transfer costs $0.15/GB (first 1TB included on Pro) — costs scale quickly on bandwidth-heavy sites
  • No native relational/vector database; beyond Blob Storage, data depends on external providers via the Marketplace
  • SAML SSO is a separate $300/mo add-on on Pro; Directory Sync (SCIM) is Enterprise-only
  • Edge PoP count (126) is more limited than Cloudflare's global footprint
  • Function-based pricing can stay more expensive than Workers for high-request, low-CPU sites

Best For

Teams that want zero-lag access to new Next.js features (PPR, Turbopack, Cache APIs)Startups and agencies iterating fast with zero DevOpsProduct teams that want a preview-deployment-driven workflowCPU-intensive but moderate-traffic SSR applications

Cloudflare (Workers + Pages)

Pros

  • No egress/bandwidth fees — only requests ($0.30/million extra) and CPU-time ($0.02/million extra CPU-ms) are billed
  • 95% of the network sits within 50ms of the internet population — very broad geographic reach
  • The V8 isolate architecture gives structurally lighter cold starts than container-based functions
  • With vinext, ~94% of the Next.js 16 API surface is now supported via a reimplementation
  • KV, R2, D1, Hyperdrive, and Durable Objects let you keep data on the same edge network
  • Access for Workers (Aug 2026) attaches identity policy directly to the Worker, regardless of route/preview URL

Cons

  • vinext is beta — you're advised to run `npx vinext check` before adopting it; the GitHub repo itself says it isn't yet a drop-in replacement for every production workload
  • The OpenNext adapter's ISR+PPR R2 cache backend carries a staleness risk after ~24 hours (Issue #662; reported against adapter v1.0.2, still open)
  • next/image optimization is only partially supported — some scenarios need extra configuration
  • Since Cloudflare doesn't originate Next.js, new framework features arrive later than on Vercel
  • The $5/mo base fee plus request/CPU-time model reduces predictability for low-traffic but CPU-heavy apps
  • The OpenNext/vinext layer adds operational overhead (adapter updates, cache backend choice)

Best For

Bandwidth-heavy sites (image/video/API-heavy) — cost stays predictable since egress is freeApplications with a global, multi-region user baseTeams that prefer a single-ecosystem data layer with KV/D1/R2/HyperdriveMulti-route internal applications that need centralized identity/access policy (Access)

Code Comparison

Vercel
// Vercel — Next.js 16 App Router, Cache Components (PPR default) + on-demand purge
// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  cacheComponents: true,
};

export default nextConfig;

// app/blog/[slug]/page.tsx — cached data with 'use cache' + cacheTag
import { cacheTag } from "next/cache";

async function getPost(slug: string) {
  "use cache";
  cacheTag(`post-${slug}`);
  const res = await fetch(`https://api.example.com/posts/${slug}`);
  return res.json();
}

export default async function BlogPost({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const post = await getPost(slug);

  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.html }} />
    </article>
  );
}

// app/api/revalidate/route.ts — on-demand purge (Vercel Data Cache)
// "max" = stale-while-revalidate; use { expire: 0 } to drop instantly on webhook
import { revalidateTag } from "next/cache";
import { NextRequest, NextResponse } from "next/server";

export async function POST(req: NextRequest) {
  const { slug } = await req.json();
  revalidateTag(`post-${slug}`, "max");
  return NextResponse.json({ revalidated: true });
}

// vercel.json — region preference and function duration
{
  "regions": ["fra1"],
  "functions": {
    "app/api/revalidate/route.ts": { "maxDuration": 10 }
  }
}

// Deploy
// $ vercel --prod
Cloudflare (Workers + Pages)
// Cloudflare — deploy Next.js 16 to Workers (vinext, official default path)
// 1) Measure compatibility first, then add to the project (Vite config is generated by vinext init)
// $ npx vinext check
// $ npx vinext init

// vite.config.ts — Workers Cache for route-level ISR, KV for data cache
import { cloudflare } from "@cloudflare/vite-plugin";
import { cdnAdapter } from "@vinext/cloudflare/cache/cdn-adapter";
import { kvDataAdapter } from "@vinext/cloudflare/cache/kv-data-adapter";
import { defineConfig } from "vite";
import vinext from "vinext";

export default defineConfig({
  plugins: [
    vinext({
      // cdnAdapter only works when wrangler.jsonc has "cache": { "enabled": true }
      cache: { cdn: cdnAdapter(), data: kvDataAdapter() },
    }),
    cloudflare({
      viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] },
    }),
  ],
});

// Deploy — it generates the Worker configuration itself
// $ npx @vinext/cloudflare deploy

// Alternative: OpenNext adapter — open-next.config.ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";

export default defineCloudflareConfig({ incrementalCache: r2IncrementalCache });
// $ opennextjs-cloudflare build && opennextjs-cloudflare deploy

// Access for Workers — attach the Worker to an Access application
// POST /accounts/{account_id}/access/apps
// "destinations": [{ "type": "worker", "worker_id": "<worker-id>" }]

Conclusion

It depends on your situation. If you want the newest Next.js features with zero lag, choose Vercel — there's no parity risk. If you're running a bandwidth-heavy, global project and prioritize predictable cost, Cloudflare is the right bet; alongside the mature OpenNext, there's now the beta but fast-moving vinext. For critical work, start with OpenNext; try vinext on a new project.

Get Free Consultation
FAQ

Frequently Asked Questions

Not fully, but close: Cloudflare's new vinext layer supports ~94% of the Next.js 16 API surface (App Router, Server Actions, ISR, middleware) and is the official default path — but it's still beta; the docs say to run `npx vinext check` before adopting it in an existing production app. The more mature `@opennextjs/cloudflare` adapter has a staleness issue (an open GitHub issue) in its R2 cache backend for ISR+Partial Prerendering.

Related Blog Posts

View All Posts

Related Projects

View All Projects
All Comparisons