July 29, 2026
Why I Moved My Portfolio to Cloudflare Pages
Deploying a personal portfolio should be boring. You push code, it goes live, nobody thinks about it again. For a while Vercel handled that for me perfectly — until I started caring more about where my traffic was being processed and what the bill might look like if a blog post ever got picked up somewhere.
Cloudflare Pages solved both concerns at once. Here's what the move looked like and what I learned along the way.
Why Cloudflare Pages
The pitch is simple: your static assets are cached at Cloudflare's edge (300+ locations), dynamic routes run as edge functions with no cold-start penalty, and the free tier is generous enough that a portfolio site will never leave it.
The catch is that edge functions are not Node.js. They run in V8 isolates — the same runtime as a browser's JavaScript engine, without fs, without process, without most of the Node.js standard library. That matters the moment you write an API route.
The Adapter Layer
Next.js by default builds for a Node.js server. To run on Cloudflare you need an adapter that transforms the build output into edge-compatible Workers. @cloudflare/next-on-pages did that job for a while; the ecosystem is now moving toward @opennextjs/cloudflare (OpenNext), which Cloudflare's own tooling now recommends when you run wrangler deploy in a Next.js project.
The adapter imposes one constraint worth knowing upfront: every API route must opt into the edge runtime explicitly.
export const runtime = 'edge';
Without that export the build fails — not at runtime, but at the Cloudflare packaging step, which is a nice property. You find out immediately rather than after a deploy.
Dependency Conflicts Are a Moving Target
The Cloudflare toolchain moves fast. wrangler, @cloudflare/workers-types, and @cloudflare/next-on-pages each version independently, and the peer dependency graph between them can break without any of your own code changing.
The pragmatic fix: commit a .npmrc with legacy-peer-deps=true. It tells npm to resolve dependencies the way npm 6 did — ignoring peer conflicts rather than failing on them. It is not elegant, but for a portfolio site it is the right trade-off between stability and time spent debugging a build pipeline.
What Stayed the Same
Everything the user sees. Pages Router, Tailwind, Framer Motion, the blog rendered from local markdown files — none of that changed. The adapter works below the framework, not inside it.
The only visible difference is latency: the site is measurably faster from locations far from a single-region server, which is exactly the promise Cloudflare makes.
Worth It?
Yes, for a static-first site with a small number of dynamic routes. If you have heavy server-side logic, streaming responses, or need full Node.js APIs, the edge runtime constraints will frustrate you. For a portfolio — a few pages, one contact endpoint, a blog — it is a good fit.