Next.js is a full-stack React framework created and maintained by Vercel, and it runs on both Vercel and Cloudflare with your application code largely unchanged. What changes between the two platforms is the server runtime, the Next.js features each one supports, the configuration and deployment workflow, and the storage and background-processing services your app connects to.
On Vercel, Next.js runs on Vercel Functions with Fluid compute, the native platform built by the team that maintains the framework. On Cloudflare, Next.js runs on Cloudflare Workers through the OpenNext Cloudflare adapter (@opennextjs/cloudflare), which transforms the Next.js build output to run on workerd, Cloudflare's V8 isolate-based runtime. This guide breaks down how the two platforms differ so you can decide which one fits your project.
In this comparison guide, you'll learn:
- How Next.js deploys and runs on Vercel and Cloudflare
- Which Next.js features each platform supports, and where support is partial
- How the Vercel Functions and Cloudflare Workers runtimes differ
- How storage and background processing map across the two platforms
- How each platform prices computing
- When to choose Vercel or Cloudflare for your project
Both platforms build the same Next.js app and deploy from Git with preview URLs: Vercel creates a preview deployment for every pull request, and Cloudflare's Workers Builds generates a preview URL for each version it builds. The differences begin at the server runtime and extend to feature support, configuration, scaling, and pricing.
| Area | Vercel | Cloudflare |
|---|---|---|
| Framework support | Native, maintained by Vercel | Next.js 16, 15, and 14 via the OpenNext Cloudflare adapter (@opennextjs/cloudflare); Next.js 14 support ends Q1 2026 |
| Build setup | Zero-config, auto-detected on import | wrangler.jsonc, open-next.config.ts, and adapter build scripts |
| Server runtime | Vercel Functions on Fluid compute, full Node.js | workerd (V8 isolates) with the nodejs_compat compatibility flag |
| Compute model | Fluid compute, enabled by default | One Worker per app, scaled as isolates across Cloudflare's network |
| Execution location | Regional; runs in the region you choose, with multi-region support on higher plans | Global; runs in the Cloudflare data center closest to each request, with optional Smart Placement |
| Memory | Up to 4 GB per function | 128 MB per isolate, fixed |
| Reading config in code | process.env | process.env for variables and getCloudflareContext().env for bindings; build-time and runtime values are set separately |
| Package manager | npm, pnpm, Yarn, or Bun | npm, pnpm, Yarn, or Bun |
| Deploy | Git push or the vercel CLI | opennextjs-cloudflare deploy or Workers Builds (GitHub and GitLab) |
The most consequential difference is the runtime itself. Vercel Functions execute your server code in a full Node.js runtime, so any npm package that works in a Node.js server works in your Next.js app without configuration. Cloudflare Workers execute code in workerd, a V8 isolate-based runtime where Node.js APIs come from a compatibility layer enabled by the nodejs_compat flag and a compatibility date of 2024-09-23 or later.
The OpenNext Cloudflare adapter runs Next.js in its Node.js runtime mode rather than the Edge runtime, which is how it supports most of the framework on Workers. Cloudflare documents the majority of Node.js APIs as full implementations, but lists others as partially supported or as non-functional stubs, so an npm package that depends on one of those gaps won't run until Cloudflare closes it.
Resource limits differ in both size and kind. Vercel Functions offer configurable memory up to 4 GB and a 250 MB function bundle. Cloudflare Workers run with a fixed 128 MB of memory per isolate and a compressed Worker size limit of 3 MB on the Workers Free plan and 10 MB on the Workers Paid plan. Cloudflare also caps subrequests, the requests your Worker makes to other services, at 50 per invocation on the Free plan and 10,000 on the Paid plan. The platforms measure compute time in different units as well: Vercel limits wall-clock duration, while Cloudflare limits active CPU time. The pricing section below explains what that distinction means in practice.
Vercel maintains Next.js, so the framework runs with full feature support, and new capabilities land on Vercel first. Cloudflare's support depends on the OpenNext Cloudflare adapter translating the Next.js build output for workerd, plus caching services you configure yourself. The adapter supports all minor and patch versions of Next.js 16, and the latest minor versions of Next.js 15 and 14, with support for Next.js 14 sunset.
| Next.js feature | Vercel | Cloudflare |
|---|---|---|
| Incremental Static Regeneration (ISR) | Supported, with pages cached and persisted to durable storage | Supported, after you configure an incremental cache (R2 recommended) and a Durable Objects revalidation queue |
| On-demand and tag-based revalidation | Supported, with global cache purges in about 300ms | Supported, after you configure a tag cache backed by D1 or Durable Objects |
use cache | Supported | Supported (experimental in Next.js), per the adapter's feature list |
| Middleware | Supported, including Node.js middleware | Supported, except Node.js middleware (Next.js 15.2 and later), which the adapter does not yet support |
Image Optimization (next/image) | Automatic, on-demand optimization with zero config | Supported through Cloudflare Images, configured with an images binding and billed separately |
| Streaming | Supported | Supported |
| Server Components and Server Actions | Supported via Vercel Functions | Supported |
For content-heavy sites, what matters most is caching, and the two platforms handle it differently:
- On Vercel, the CDN manages
Cache-Controlheaders and ISR without configuration. Pages persist to durable storage, and on-demand or tag-based revalidation purges content globally in about 300ms. - On Cloudflare, you assemble the cache from platform services in
open-next.config.ts: an R2 bucket for the incremental cache, a Durable Objects queue for time-based revalidation, and a D1 database or sharded Durable Objects for the tag cache. Headers set innext.config.tsdon't apply to static assets, which Cloudflare serves withmax-age=0, must-revalidateby default, so long-lived asset caching goes in apublic/_headersfile. Automatic cache purging requires a custom domain and an API token stored as a secret.
Vercel Functions run regionally: you choose the region your functions execute in, and Pro and Enterprise plans can run functions in multiple regions. Cloudflare Workers run globally by default, in the Cloudflare data center closest to each request, and the optional Smart Placement feature can instead run a Worker closer to the back-end services it calls when that lowers total request time.
Proximity to the user helps short, compute-light responses, while proximity to your data usually matters more for server rendering. Pages that make several database queries pay the function-to-database round trip on every query, so running the function in the region next to the database often beats running it at the edge. Cloudflare's own caching layer shows the same tension: the R2 bucket backing the adapter's incremental cache holds its data in a single region, which is why the adapter offers a regional cache wrapper to keep ISR reads closer to your visitors.
Vercel deploys a standard Next.js app with zero configuration. You import a repository from GitHub, GitLab, or Bitbucket, Vercel detects the framework and sets the build command, and every pull request gets its own preview URL. Code reads configuration from process.env at both build time and runtime, and a vercel.json file is optional for settings like function regions or cron schedules.
Cloudflare requires configuration before the first deploy. A working setup includes wrangler.jsonc to define the Worker, open-next.config.ts for the adapter's caching setup, a .dev.vars file for local development, a public/_headers file for static asset caching, and an initOpenNextCloudflareForDev() call in next.config.ts so bindings work during next dev.
The wrangler.jsonc file is the most distinctive piece:
Deploys run through the adapter CLI: opennextjs-cloudflare build runs next build and transforms the output, opennextjs-cloudflare preview serves the app locally in workerd, and opennextjs-cloudflare deploy populates the remote cache and deploys through Wrangler. The adapter's documentation calls out three details worth planning for. Build-time variables, including the NEXT_PUBLIC_ values Next.js inlines during the build, are configured separately from runtime variables when you use Workers Builds. Deploying can overwrite variables set in the Cloudflare dashboard unless you pass --keep-vars. And full Windows support isn't guaranteed; the OpenNext docs recommend WSL or a Linux-based CI system.
The clearest code-level difference between the platforms is how storage reaches your code.
Cloudflare uses bindings: you declare each R2 bucket, KV namespace, or D1 database in wrangler.jsonc and access it through getCloudflareContext().env, with wrangler types generating the TypeScript definitions (static-generation code uses the async form, getCloudflareContext({ async: true })).
On Vercel, storage comes from first-party products and the Vercel Marketplace, where provisioning a store wires its credentials into environment variables automatically, and code reads them through process.env and the provider's SDK.
| Need | Cloudflare | Vercel |
|---|---|---|
| Object storage | R2 | Vercel Blob |
| Key-value and caching | Workers KV | Redis from the Marketplace, or Edge Config for read-heavy config |
| SQL database | D1 | Postgres from the Marketplace |
| AI inference | Workers AI | AI Gateway with AI SDK |
R2 is S3-compatible object storage with no egress charges, which matters when you serve large files at volume. Workers KV is eventually consistent, a property the OpenNext docs cite when recommending against it for the ISR cache. Cloudflare also offers Durable Objects, a stateful coordination primitive with no direct Vercel equivalent, which the adapter itself uses for revalidation queues and high-traffic tag caches.
Both platforms ship first-party services for scheduled work, queues, and durable workflows, so background processing maps one-to-one. The differences are in execution limits and packaging rather than missing products.
| Need | Cloudflare | Vercel |
|---|---|---|
| Scheduled jobs | Cron Triggers | Vercel Cron Jobs |
| Message queues | Cloudflare Queues | Vercel Queues |
| Durable, multi-step processes | Cloudflare Workflows | Vercel Workflows |
Vercel Workflows run durable steps that pause, resume, and retain state from minutes to months. Cloudflare Workflows take a similar shape, with durable, multi-step execution, automatic retries, and state that persists for minutes, hours, or weeks, and are available on both Free and Paid plans. Around them, Cloudflare caps Cron Triggers and queue consumers at 15 minutes of wall-clock time per invocation, and Cloudflare Queues includes 10,000 operations per day on the Free plan and 1 million operations per month on the Paid plan, with $0.40 per million operations beyond that.
Vercel and Cloudflare both bill compute time based on active CPU time rather than wall-clock time, so neither platform charges for the time your code spends waiting on a database or an upstream API. The mechanics and packaging differ from there.
Vercel bills three meters with Fluid compute: Active CPU at $0.128 per hour, billed only while your code executes; Provisioned Memory at $0.0106 per GB-hour while a request is in flight; and a per-invocation charge. Nothing is billed between requests, and in-function concurrency lets a warm instance serve multiple requests at once, which reduces both cold starts and memory costs. The Hobby plan includes function usage at no cost, and Pro and Enterprise plans bill usage beyond their included allotments.
Cloudflare packages compute into two plans.
Workers Free includes 100,000 requests per day with up to 10 ms of CPU time per invocation. Workers Paid costs $5 per month and includes 10 million requests and 30 million CPU milliseconds per month; usage beyond that is billed at $0.30 per million requests and $0.02 per million CPU milliseconds. Duration isn't charged or limited on the Paid plan, and memory isn't metered, since every isolate gets the same 128 MB. Cloudflare adjusts these allotments periodically, so check the pricing page for current figures.
The execution limits also measure different things, which matters when you compare them:
| Limit | Vercel | Cloudflare |
|---|---|---|
| Compute time per request | Wall-clock duration up to 300s (Hobby) and 800s (Pro and Enterprise) | Active CPU time: 10 ms (Free); 30s by default, configurable up to 5 minutes (Paid). No wall-clock limit while the client stays connected |
| Memory | Up to 4 GB | 128 MB per isolate, fixed |
| Bundle size | 250 MB | 3 MB compressed (Free), 10 MB compressed (Paid) |
| Beyond the limit | Vercel Workflows for minutes-to-months processes | Cloudflare Workflows; Cron Triggers and queue consumers allow up to 15 minutes of wall-clock time |
A wall-clock limit includes time spent waiting; a CPU limit doesn't. A Cloudflare Worker that spends 20 seconds waiting for an LLM response consumes almost none of its CPU budget, while CPU-bound work, such as rendering large pages, parsing large payloads, or processing images, consumes that budget directly, with the fixed 128 MB ceiling applying throughout. On Vercel, the same CPU-heavy work runs inside the 300s or 800s wall-clock window with whatever memory you configure, up to 4 GB.
The day-to-day workflow looks similar on both platforms: push to Git, get a build, review a preview URL, promote to production. Both detect Next.js, and running npx wrangler deploy in a Next.js project can even generate the Worker configuration automatically.
Vercel layers framework-aware infrastructure on that flow. ISR, Image Optimization, and Draft Mode work without configuration, and observability, the Vercel Firewall, and instant rollbacks come with every deployment.
Cloudflare's strengths center on runtime parity and its wider platform. opennextjs-cloudflare preview runs your app locally inside workerd, the same runtime that serves production traffic, and remote bindings let local development read real R2, KV, or D1 data. The opennextjs-cloudflare upload command stages a new version without serving it, which supports gradual rollouts. And if your DNS, CDN, or security already runs on Cloudflare, Workers keeps the application on the same platform and dashboard. The trade-off is the adapter itself: it adds a second build step, its own configuration surface, and a feature lag whenever Next.js ships something the adapter hasn't yet translated, with Node.js middleware as the current example.
The framework is the same on both platforms, so the decision comes down to feature support, runtime compatibility, where your code needs to run, and how the app fits the rest of your stack.
| If your project... | Consider | Why |
|---|---|---|
Needs full Next.js feature support, including ISR, use cache, and Node.js middleware | Vercel | As the native Next.js platform, Vercel supports the full framework with no adapter gaps |
| Depends on npm packages that need full Node.js APIs | Vercel | Runs in a full Node.js runtime with no compatibility flags |
| Relies on HTTP caching and on-demand or tag-based revalidation | Vercel | The CDN manages Cache-Control and ISR purges content globally in about 300ms, with no cache services to assemble |
| Is I/O-bound or AI-heavy, with LLM calls, agents, or MCP servers | Vercel | Fluid compute and Active CPU pricing avoid billing CPU during waits, and Workflows handle long jobs |
| Runs memory-heavy or long CPU-bound work per request | Vercel | Function memory is configurable up to 4 GB, with durations up to 800s on Pro and Enterprise, against a fixed 128 MB per Worker isolate |
| Already runs DNS, CDN, or security on Cloudflare | Cloudflare | Workers, R2, D1, and KV share one platform and dashboard, and bindings connect them without managing credentials |
| Serves a globally distributed audience with short, compute-light responses | Cloudflare | Workers run in the Cloudflare data center closest to each request by default |
| Serves large files where egress costs dominate | Cloudflare | R2 charges nothing for egress bandwidth |
| Wants a low, predictable starting price for compute | Cloudflare | Workers Paid costs $5 per month and includes 10 million requests and 30 million CPU milliseconds |
Many teams successfully run Next.js on either platform.
Choose Vercel when you want the full Next.js feature set with no adapter or cache services to maintain, full Node.js compatibility, configurable memory and duration, and first-party storage and background processing. Choose Cloudflare when your infrastructure already runs there, your traffic is global with short compute-light responses, or R2's free egress and the $5 per month Workers Paid plan fit your cost model.