billing hacks
Cloudflare Deep DiveOverview

Cloudflare Deep Dive

The promise and pitfalls of running Next.js on Cloudflare. What works, what breaks, and when to make the switch.

Advanced Topic

Cloudflare migration is high-effort, high-reward. Only consider if you've exhausted Vercel optimizations and costs are still problematic. Most apps should start with simpler optimizations.

Cloudflare's edge network is tempting. Global distribution, generous free tier, no cold starts. But Next.js wasn't built for Workers. Here's the reality.

The Appeal

Vercel costs scale with compute time. A function that runs 500ms costs 5x more than one that runs 100ms. Cloudflare Workers have a different model:

MetricVercelCloudflare Workers
Free requests100K/month100K/day
Compute pricingPer GB-hourPer request (after free)
Cold startsYes (serverless)No (isolates)
Global edgePaid add-onDefault

Cloudflare's pricing can be 10-50x cheaper for high-traffic sites with simple compute needs.

The Catch

Next.js assumes Node.js. Cloudflare Workers run V8 isolates. This gap creates friction at every layer:

┌─────────────────────────────────────────────────┐
│                   Next.js                        │
│  (Node.js APIs, fs, crypto, Buffer, streams)    │
├─────────────────────────────────────────────────┤
│              @opennextjs/cloudflare              │
│         (Compatibility layer, adapters)          │
├─────────────────────────────────────────────────┤
│              Cloudflare Workers                  │
│    (V8 isolates, Web APIs, no Node.js)          │
└─────────────────────────────────────────────────┘

Deployment Options

The @opennextjs/cloudflare adapter is the current best path:

npm install @opennextjs/cloudflare
open-next.config.ts
import type { OpenNextConfig } from "@opennextjs/cloudflare";

export default {
  buildCommand: "npx next build",
  // Cloudflare-specific options
} satisfies OpenNextConfig;

2. Static Export (Safest)

If you can go fully static, Cloudflare Pages just works:

next.config.js
module.exports = {
  output: 'export',
};

No runtime issues. No compatibility problems. But no SSR, no API routes, no dynamic features.

3. Edge Runtime (Partial)

Force specific routes to edge runtime:

app/api/fast/route.ts
export const runtime = 'edge';

export async function GET() {
  // Only Web APIs available here
  return Response.json({ time: Date.now() });
}

What You're Giving Up

Before migrating, understand what breaks:

FeatureVercelCloudflare
fs module✅❌
Native Node modules✅❌
next/image optimization✅ Built-in⚠️ Needs setup
ISR (revalidation)✅⚠️ Different behavior
Streaming SSR✅⚠️ Limited
Middleware✅✅ (edge only)
API Routes✅⚠️ Edge-compatible only

Continue to Runtime Limitations for specific APIs that break and their workarounds.

On this page