Cloudflare Workers vs Vercel Edge: A Latency-Cost Comparison
We deployed the same edge function on both platforms and measured for a quarter. Where each wins, where each loses, and the surprises along the way.
Key takeaways
- We deployed the same edge function on both platforms and measured for a quarter.
- Where each wins, where each loses, and the surprises along the way.
On this page
Cloudflare Workers vs Vercel Edge: A Latency-Cost Comparison#
We deployed the same edge function on both Cloudflare Workers and Vercel Edge for a full quarter. Same code, same inputs, same upstream. Both running globally, both production-grade. Here's the breakdown of where each wins, where each loses, and what surprised us most.
What We Deployed#
A simple but representative edge function: an A/B-test cohort assigner.
- Reads a request cookie or generates a new cohort ID
- Looks up cohort → variant in a KV store
- Sets the cookie if missing
- Adds a header for downstream caching
- Returns the original response from origin
Code: about 80 lines of TypeScript. Runs on every request to the marketing site (~14M requests/day at peak).
The Two Stacks#
Cloudflare Workers#
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const cohort = await getOrCreateCohort(request, env);
const variant = await env.KV.get(`cohort:${cohort}`) ?? "control";
const response = await fetch(request, {
headers: { ...request.headers, "x-variant": variant },
});
const newResp = new Response(response.body, response);
newResp.headers.set("set-cookie", `cohort=${cohort}; Path=/; Max-Age=31536000`);
return newResp;
},
};
Deployed via wrangler publish. KV reads from Cloudflare KV.
Vercel Edge#
import { NextRequest, NextResponse } from "next/server";
export const config = { runtime: "edge" };
export async function middleware(request: NextRequest) {
const cohort = await getOrCreateCohort(request);
const variant = await fetch(`https://kv.upstash.io/get/cohort:${cohort}`).then(r => r.text());
const response = NextResponse.next({
headers: { ...request.headers, "x-variant": variant },
});
response.cookies.set("cohort", cohort, { maxAge: 31536000 });
return response;
}
Deployed as Next.js middleware. KV reads from Upstash (Vercel's edge function doesn't have native KV in the same shape).
The Numbers#
Measurements are p50/p95/p99 of total edge-function execution time, not including upstream-fetch time. Sampled across a quarter, geographic distribution roughly weighted to our user base (~60% NA, ~30% EU, ~10% rest).
| Metric | Cloudflare Workers | Vercel Edge |
|---|---|---|
| Cold start (95p) | 4ms | 38ms |
| Hot p50 | 2.1ms | 9.2ms |
| Hot p95 | 5.4ms | 21ms |
| Hot p99 | 12ms | 42ms |
| KV read p95 (regional) | 1.8ms | 8.4ms |
| Global PoPs | 330+ | ~70 |
Cloudflare wins on raw latency by a wide margin. Two reasons:
- More PoPs. CF runs in 330+ cities; Vercel Edge has fewer locations and routes to its own infrastructure.
- Native KV. CF KV is colocated with the Worker; Upstash KV adds a network hop even when in the same region.
Cost Math#
| CF Workers | Vercel Edge | |
|---|---|---|
| Base plan | $5/mo | included with hosting |
| Per-request beyond plan | $0.30/M | $2.00/M (rounded across products) |
| KV read | $0.50/M | depends on KV provider |
| KV write | $5/M | depends on KV provider |
| Outbound bandwidth | included | included |
For our 14M req/day workload, we needed paid tiers on both:
- CF Workers: 14M × 30 ≈ 420M req/mo. With KV: ~$300/mo total.
- Vercel Edge: ~$650/mo for the request volume + $120/mo for Upstash KV ≈ $770/mo total.
CF was about 2.5× cheaper for our workload.
What Surprised Us#
1. Vercel's "edge" is real but not as edge-y#
Vercel Edge runs in regional zones, not literally at every CDN PoP. For requests far from those zones, the "edge function" is sometimes 30+ms away. CF Workers actually run at the PoP serving the user.
This matters most for users in regions like LATAM, Africa, and parts of Asia. CF served them in single-digit milliseconds; Vercel sometimes routed them to a US zone with 80+ms RTT.
2. Cold starts on Vercel were a real factor#
CF Workers' V8 isolates reset in roughly 4ms. Vercel Edge cold starts (when the function had been idle for a while) regularly hit 38ms+. For a function that runs on every request, this matters because traffic patterns rotate through enough PoPs that you hit fresh isolates often.
We tried Vercel's "regional functions" mode to keep functions warm. It helped (p95 cold start dropped from 38ms to 18ms) but cost more.
3. Cloudflare's API has rough edges#
Wrangler is fine. The web UI is unfortunate. Cloudflare's docs are thorough but sometimes inconsistent (multiple ways to set the same thing; some guides outdated). Vercel's developer experience for the same complexity is meaningfully better.
We spent ~3 days more on CF setup than Vercel due to this.
4. Vercel's Next.js integration is genuinely seamless#
If your app is Next.js and you're using middleware.ts, Vercel Edge is essentially "the obvious place" for that code. Code, deploys, env vars all unify.
CF requires you to write the middleware as a separate Worker, point your DNS at it, and proxy back. The proxy adds another hop and another failure mode.
5. CF KV's eventual consistency caught us once#
CF KV is eventually consistent across PoPs. We had a "user just signed up, immediately hits another page" flow that occasionally read stale state. We mitigated by also writing to a strongly-consistent store and using KV as a cache.
Upstash (with Vercel) was strongly consistent by default in our config. One less footgun.
When Each Wins#
Cloudflare Workers wins if:#
- Latency budget is tight (sub-10ms p95 globally).
- Workload is request-volume-heavy. Cost favors CF at scale.
- You serve users globally, especially outside NA/EU. The PoP coverage matters.
- You're not deeply integrated with Next.js or a Vercel-shaped framework.
Vercel Edge wins if:#
- You're already on Vercel for hosting. Integration trivializes setup.
- Your workload is occasional-and-stateful rather than every-request. Cold starts matter less.
- Latency budget is generous (50ms+ is fine).
- DX matters more than dollars. Vercel's developer experience is significantly nicer.
What We Actually Run#
After the quarter we kept Cloudflare Workers for the cohort assigner and any other always-on edge logic. The cost and latency math was decisive for that workload.
But we kept Vercel Edge for two other functions: a redirect handler tied to our marketing CMS and an auth-token verifier for our staff app. Both benefit more from Vercel's ecosystem fit than from CF's latency.
The lesson: don't pick one for everything. Pick per workload based on what the workload's bottleneck actually is.
Architecture Patterns That Work#
Once you accept multi-platform edge, a few patterns simplify life:
1. Workload routing via DNS, not code#
Send api.example.com to one platform, assets.example.com to another. Don't try to load-balance between them in code; route at DNS.
2. Shared schema for KV#
Whatever KV provider you use on each platform, agree on a key schema across them. We use namespace:type:id everywhere; same lookup logic, different backends.
3. Observability per platform#
Both platforms log differently. We pipe both into Datadog with platform-tagged metrics so a dashboard can show "edge p99 by platform" side by side.
4. Local development stays uniform#
Both platforms can be run locally with their CLIs. Pin those CLIs in your dev container so the local dev experience is the same regardless of where the function ends up running.
Best Practices Regardless of Choice#
- Measure under your actual traffic shape. Synthetic load tests miss the bursty, geographic, and cold-start patterns that matter.
- Pin and review platform versions. Both CF and Vercel ship runtime updates; one of them once broke our deployment via a default change.
- Don't put critical state at the edge. Edge KV is great for caches; it's bad for source of truth.
- Monitor egress to origin. Edge functions that fan out to origin can quickly become an origin-load problem.
- Have a kill switch. A way to bypass edge logic and serve straight from origin. We've used ours twice in 9 months; both times it saved an incident.
What I'd Do Differently#
- Start with CF for raw latency-sensitive paths. We started everything on Vercel Edge and had to migrate; should have benchmarked first.
- Avoid the edge for state. We initially used edge KV as primary store for some flags; moved to a centralized store with edge cache. Better behavior, simpler debugging.
- Be explicit about which platform owns which path. "All edge code goes to X" doesn't survive contact with reality. Document per workload.
The right answer isn't a platform; it's the right tool per workload. Most teams don't need both. The teams that do should structure for it from day one rather than discover it later.
Get the DevOps Troubleshooting Cheat Sheet
Subscribe and get our free one-page reference for the errors that eat an afternoon — CrashLoopBackOff, OOMKilled, Terraform state locks, and more — plus new guides as we publish them.
eBPF for SREs: Three Real Diagnoses That Saved Hours
We started using eBPF tooling for ad-hoc production debugging six months ago. Three real incidents where it cut investigation time from hours to minutes.
Backstage Adoption: From Demo to 80% Service Coverage in 6 Months
We launched Backstage in October. Six months in, 80% of services are catalogued, on-boarding takes a third of the time, and we mostly know what owns what.
More from Cloud
Explore more articles in this category
Best Serverless Databases in 2026 (Compared)
A practitioner comparison of the leading serverless databases by use case, cold-start behavior, branching, pricing model, and lock-in.
Cloudflare D1: The Edge SQLite Database Guide (2026)
A practitioner's look at Cloudflare D1, the serverless SQLite database built for Workers, covering setup, read replication, limits, and fit.
Neon vs PlanetScale: Serverless SQL Compared (2026)
A practitioner comparison of Neon's serverless Postgres against PlanetScale's Vitess-backed MySQL to help you pick the right database.
You might have missed
Evergreen posts worth revisiting.