Vercel vs Cloudflare for a static Next.js site: what I measured from Nairobi

I'm Kai Khalid, in Nairobi, and I run my own website the way I'd want an operations team to run anything: write down what "better" means before you look at the numbers. This is the field report from moving kaikhalid.com off Vercel and onto Cloudflare, with what I measured, what broke, and what the data does not show.
What I moved
kaikhalid.com is a 14-page Next.js 16 portfolio. It needs no server, so I built it with output: 'export' (Next.js static exports): 173 files, about 6 MB. On Cloudflare it runs as Workers static assets, deployed by Workers Builds on each push. Deploys took 58.5–71.5 seconds.
Three changes were needed:
- Images. A static export can't use Vercel's
/_next/imageoptimiser. I replaced it with a 118-line build-time script that converts images to WebP using sharp at quality 75. 44 files came out byte-identical to the originals. - Headers. HSTS and cache rules moved into a _headers file.
- Redirects. The www → apex redirect became a Cloudflare dashboard rule.
How I tested
- Same code on both hosts: the same build, deployed to Vercel and Cloudflare.
- One machine: a Mac on one network in Kenya, on 16 October 2026.
- Pre-registered decision rule: Cloudflare "wins" only if Lighthouse LCP is better by more than 100 ms in at least 3 of 4 cells (mobile/desktop × home/post page).
- TTFB: fresh connection each time, DNS excluded, 100 interleaved pairs × 2 rounds. 1,200 requests in total, all HTTP 200 with a cache HIT.
- Lighthouse: Lighthouse 13.5.0, simulated throttling, 10 runs per cell.
- Noise control: an A/A test (same host vs itself) gave a noise floor of about ±70 ms on desktop and ±400 ms on mobile.
Results: time to first byte (from Kenya)
| Metric | Vercel | Cloudflare | Difference |
|---|---|---|---|
| Median TTFB | ~302–328 ms | 47–59 ms | ~246–262 ms faster on Cloudflare |
| Pairs where Cloudflare was faster | – | 95–99% | – |
| TLS handshake | 200 ms | 21 ms | 179 ms |
| Server wait | 111 ms | 24 ms | 87 ms |
| Edge that served the request | Cape Town (cpt1) | Nairobi (NBO) | – |
Most of the gap is geography. A TLS handshake needs round trips, and round trips to Cape Town cost more than round trips across town.


Results: Largest Contentful Paint (Lighthouse, simulated)
| Cell | Vercel LCP | Cloudflare LCP | Cloudflare advantage | Scores (V / CF) | Clears 100 ms bar? |
|---|---|---|---|---|---|
| Mobile, home | 2954 ms | 2280 ms | +675 ms | 88.5 / 98 | Yes |
| Mobile, post | 3094 ms | 2563 ms | +531 ms | 88 / 97 | Yes |
| Desktop, home | 529 ms | 607 ms | −79 ms | 100 / 100 | No |
| Desktop, post | 519 ms | 595 ms | −77 ms | 100 / 100 | No |
Two caveats matter. The mobile gains sit inside a ±400 ms noise floor, though both are larger than it. The desktop lead for Vercel is only just outside the ±70 ms floor.


Cloudflare injects a Web Analytics beacon (10.4 KB, 4 requests). Blocking it did not close the desktop gap, so the cause is still unexplained. Unthrottled desktop runs pointed the other way: home LCP 676 ms on Vercel vs 361 ms on Cloudflare (significant), post 810 vs 371 ms (not significant).
Outside Kenya
A 34-node global checker found Cloudflare faster in 23 locations and Vercel in 11, with a median of 49 ms in Cloudflare's favour. Vercel was faster in parts of western Europe (Germany: 49 ms vs 154 ms) and in Hong Kong. If your audience is mainly in Frankfurt, test from there before you decide.

Migration gotchas
- Error 100117 when attaching the custom domain. Cloudflare refuses if an existing A or CNAME record is already on that hostname. Remove the old record, then attach.
- The www redirect is now invisible from the repo. It lives in a dashboard rule. That's a configuration drift risk: anyone reading the code won't know it exists. Document it, or move it into code.
- Free-tier terms. Vercel's Hobby plan is for non-commercial, personal use, and keeps runtime logs for only one hour. See Vercel pricing. I have not yet checked Cloudflare's free-plan terms in the same detail. Do that before you rely on it.
- Image optimisation is now your job. No
/_next/imagein a static export, so plan a build step.
Which should you choose?
| If… | Lean towards |
|---|---|
| Most visitors are in Kenya or East Africa and the site is static | Cloudflare, based on this test |
| You rely on Next.js server features (SSR, ISR, middleware, `/_next/image`) | Vercel: a static export removes these |
| Your audience is mainly in western Europe | Test first; Vercel was faster in Germany here |
| Desktop Lighthouse is your main KPI | Neither clearly; the gap was ~78 ms, close to noise |
| The site earns money and you're on a free tier | Read the terms: Vercel Hobby is non-commercial |
| You want every setting visible in Git | Either, but keep redirects in code, not dashboards |
What this does not show
- One network, one location, one machine. Geography drives much of the gap.
- No real-user data. These are lab and synthetic numbers.
- Chrome only. No Safari or Firefox.
- Cost and behaviour under load were not tested.
- The Vercel copy runs today's code, not the exact historical deployment.

Get the data
All the raw numbers behind this post are open: 1,200 curl timings, 280 Lighthouse runs and the multi-region check, with the pre-registration and analysis scripts, are at kaikhalid.com/data/benchmark-2026-10-16 under CC BY 4.0. Download the ZIP, check my medians, or rerun the analysis. If you reuse it, please cite: Khalid, K. (2026). Vercel vs Cloudflare TTFB and Lighthouse benchmark from Nairobi [Data set]. https://kaikhalid.com/data/benchmark-2026-10-16.
FAQ
Is Cloudflare faster than Vercel for a Next.js site?
In my test from Kenya, yes for time to first byte (~250 ms faster at the median) and mobile LCP. Vercel was slightly faster on desktop Lighthouse LCP, and faster from parts of western Europe and Hong Kong.
Why was Cloudflare faster from Nairobi?
It served requests from its Nairobi location, while Vercel served from Cape Town. The TLS handshake alone dropped from 200 ms to 21 ms.
Can a Next.js site run on Cloudflare Workers?
A static export can, using Workers static assets. You lose server-side features and Vercel's image optimiser, so you'll need a build-time image step.
What is Cloudflare error 100117?
It appeared when I attached a custom domain to the Worker while an existing A or CNAME record was still on that hostname. Removing the old record fixed it.
Can I use Vercel's free plan for a business site?
Vercel's Hobby plan is for non-commercial personal use. Check the current terms on Vercel's site.
I also posted this as a thread on X
