Content Delivery Network Blog

NextJS Cloudflare Deployment Guide: Pages, Workers and Images

Written by BlazingCDN | May 27, 2025 12:33:42 AM

Deploy Next.js to Cloudflare in 2026: A Production Playbook

Cloudflare's Q1 2026 platform report shows Workers now cold-start in under 3 ms on the P99, down from roughly 12 ms two years ago. That single metric changed the calculus for anyone deciding where to deploy Next.js to Cloudflare: full-stack SSR at the edge is no longer a compromise — it is the faster path. This playbook gives you the concrete deployment topology, the OpenNext configuration that actually works as of April 2026, a decision matrix for Pages vs. Workers vs. hybrid, a production diagnostics-and-rollback procedure the current top-10 results do not cover, and a Cloudflare Images integration pattern that eliminates your origin image pipeline entirely.

Why Deploy Next.js to Cloudflare in 2026?

Next.js 15.2 (stable as of March 2026) ships with the App Router fully mature, Partial Prerendering (PPR) enabled by default in production mode, and Server Actions that compile down to thin RPC calls. Cloudflare's runtime has kept pace: Workers run on workerd v1.20260401, which supports Node.js compat flags broad enough to cover every Next.js server dependency except sharp (handled by Cloudflare Images instead). The result is a stack where static shells stream from Pages' edge cache in single-digit milliseconds, dynamic chunks execute in Workers colocated within the same Cloudflare colo, and images transform on-read with zero origin involvement.

Vercel remains the zero-config default, but its pricing model penalizes sustained traffic. At 10 million monthly requests with moderate function invocation time, Vercel's Pro tier plus function overages can run $400–$800/month (as of Q1 2026 published pricing). A comparable Cloudflare Pages + Workers Paid setup lands at $25/month flat for most projects, with Workers Unbound billing at $0.015 per million additional requests and 12.50 per million ms of CPU time. For teams already invested in Cloudflare's network layer, collapsing the hosting bill into the same account is operationally simpler, too.

Pages vs. Workers vs. Hybrid: A Decision Matrix

This is where most guides hand-wave. Here is a workload-profile matrix based on production patterns observed across SaaS, media, and e-commerce deployments as of 2026.

Workload Profile Recommended Target Why
Marketing site, docs, blog — no auth, no dynamic routes Cloudflare Pages (static export) Pure static. Zero cold starts. Free tier covers most volumes.
App with auth, API routes, server components, but no streaming SSR Pages with Functions (Workers-backed) Pages Functions run on Workers under the hood. Single deploy artifact. Git-push workflow preserved.
Heavy SSR, PPR, streaming, WebSocket routes, cron-triggered ISR Workers directly via OpenNext Full control over worker bindings, Durable Objects for state, R2 for cache storage, KV for incremental cache.
Hybrid: static marketing + authenticated dashboard under one domain Pages (static routes) + Worker (dynamic routes) behind a single Cloudflare zone Route rules split traffic. Static paths hit the edge cache. Dynamic paths invoke the Worker. One domain, one TLS cert, one set of page rules.

How to Deploy Next.js to Cloudflare Pages (Static Export)

For a purely static Next.js site, the pipeline is straightforward. In your next.config.js, set output to "export". Connect your Git repository in the Cloudflare dashboard under Workers & Pages, set the build command to "npx next build", and the output directory to "out". Cloudflare Pages runs the build on each push, deploys the result to its edge, and gives you preview URLs per branch. Build limits as of April 2026: 500 builds per month on the free tier, 5,000 on the paid plan at $5/month.

The critical detail most guides omit: if your static site uses next/image without a custom loader, the build will fail because next/image defaults to the Vercel image optimizer. You must either set images.unoptimized to true (and handle optimization externally via Cloudflare Images) or write a custom loader pointing at the Cloudflare Images transformation endpoint. The latter is the correct production choice.

How to Deploy Next.js to Cloudflare Workers with OpenNext

OpenNext (opennextjs-cloudflare) reached its 1.0 GA milestone in February 2026. This matters because prior versions required patching Next.js internals. The 1.0 adapter works against unmodified Next.js 14.x and 15.x builds. The adapter translates the Next.js server output into a Worker-compatible entry point, maps the incremental cache to either KV or R2 (configurable), and handles the routing manifest.

To configure opennextjs-cloudflare for Next.js: install the adapter as a dev dependency, add a wrangler.toml with your KV namespace binding for the cache and an R2 bucket binding for large assets, and set the build command to "npx opennextjs-cloudflare build". The adapter produces a worker directory that Wrangler deploys directly. ISR revalidation works via a background fetch that writes the new page to KV on the next request after the stale window expires — identical behavior to Vercel's ISR, but backed by Cloudflare's KV eventual consistency model (global propagation in under 60 seconds per Cloudflare's 2026 SLA).

Bindings You Will Actually Need

KV for the page cache. R2 for static assets exceeding KV's 25 MiB value limit. A Durable Object if your app uses draft mode or preview tokens that require strongly consistent session state. Environment variables for secrets — never hardcode API keys in wrangler.toml; use wrangler secret put.

How to Use Cloudflare Images with next/image

Cloudflare Images charges $5 per 100,000 stored images and $1 per 100,000 transformation requests (2026 pricing). For most apps this replaces an entire sharp/imgproxy pipeline and the compute behind it. To wire it into Next.js, create a custom image loader that returns URLs in the format: https://imagedelivery.net/<account-hash>/<image-id>/<variant-or-transforms>. Set images.loader to "custom" and images.loaderFile to the path of your loader module in next.config.js. The loader receives width, quality, and src, and maps them to Cloudflare's transformation parameters (w, q, fit, format set to auto for AVIF/WebP negotiation). This gives you responsive, format-negotiated images served directly from Cloudflare's edge with no origin round-trip.

Diagnostics and Rollback: The Section Nobody Writes

Deployments fail. Here is how to diagnose and recover without downtime.

Symptom: 1101 Worker threw exception. Check wrangler tail in real time. The most common cause with OpenNext is a missing binding — the adapter tries to access a KV namespace that is not declared in wrangler.toml. Fix the binding, redeploy. Rollback: Cloudflare Pages keeps every deployment immutable. In the dashboard, click the previous successful deployment and hit "Rollback." Traffic shifts in under 30 seconds. For Workers deployed directly via Wrangler, use wrangler rollback to revert to the prior version.

Symptom: stale pages after ISR revalidation. KV propagation is eventually consistent. If a region sees stale data beyond 60 seconds, verify that the KV write succeeded by querying the KV namespace via the API with the page's cache key. A common pitfall: the Worker runs out of CPU time before the background revalidation fetch completes, so the KV write never fires. Increase the CPU limit in wrangler.toml (Workers Unbound allows up to 30 seconds of CPU).

Symptom: images returning 404 after migration. Confirm that image IDs in your CMS match the IDs in your Cloudflare Images account. A mismatch typically means the migration script uploaded with a different naming scheme. Use the Cloudflare Images bulk API to list all image IDs and diff against your CMS database.

Where Your CDN Layer Fits

Cloudflare Pages and Workers handle compute and static delivery at the edge, but many production architectures also serve heavy media — video, large downloads, software update bundles — that benefit from a dedicated CDN with volume-based pricing. BlazingCDN's SaaS delivery infrastructure provides stability and fault tolerance on par with Amazon CloudFront while starting at $4 per TB ($0.004/GB) for smaller workloads and dropping to $2 per TB at 2 PB+ commitments. For teams running Next.js on Cloudflare for the application layer but offloading large-asset delivery to a cost-optimized CDN, that pricing gap compounds fast — especially for SaaS platforms with global user bases pushing tens of terabytes monthly.

FAQ

Can I deploy a full-stack Next.js app to Cloudflare Pages without OpenNext?

Only if your app is purely static (output: "export"). The moment you use API routes, server components, or middleware that runs at request time, you need either Pages Functions (which are Workers under the hood) or the OpenNext adapter to translate Next.js server output into a Worker entry point. As of April 2026, Cloudflare's native Pages framework integration does not support Next.js server mode without the adapter.

How does Cloudflare Pages vs. Workers for Next.js differ in practice?

Pages gives you a Git-connected CI/CD pipeline, preview deployments per branch, and instant rollback — at the cost of less control over Worker bindings. Workers deployed via Wrangler give you direct access to Durable Objects, custom Cron Triggers, and fine-grained routing, but you manage the deploy pipeline yourself. For most teams, Pages with Functions is the default; switch to raw Workers when you need bindings that Pages Functions do not expose.

Does next/image work out of the box on Cloudflare?

No. The default Image Optimization API targets Vercel's infrastructure. On Cloudflare you must either disable optimization (images.unoptimized: true) or set a custom loader pointing to Cloudflare Images or Cloudflare Image Resizing. The custom loader approach is strongly preferred because it gives you AVIF/WebP auto-negotiation and edge-cached transformations at $1 per 100K requests.

What is the cold-start latency for Next.js on Cloudflare Workers in 2026?

Cloudflare reports sub-3 ms P99 cold starts for Workers as of Q1 2026. In practice, an OpenNext-compiled Next.js Worker with moderate bundle size (under 5 MB after tree-shaking) initializes in 4–8 ms P99 including JavaScript evaluation. This is roughly 10x faster than a comparable AWS Lambda@Edge cold start.

How do I handle environment variables and secrets?

Use wrangler secret put for anything sensitive. Non-secret config goes into the [vars] section of wrangler.toml. For Pages, set environment variables in the dashboard under Settings — Environment Variables. Never commit secrets to the repository; Cloudflare encrypts secrets at rest and injects them at runtime.

Ship It, Then Measure

If you are sitting on a Next.js deployment that still round-trips to a traditional origin, here is your action item for this week: take your highest-traffic dynamic route, deploy it to a Cloudflare Worker via OpenNext, and instrument it with Server-Timing headers that report cache-status, worker-init-ms, and upstream-fetch-ms. Compare the P50 and P99 against your current setup. The numbers will make the architecture decision for you. Post your before/after in the Cloudflare Developers Discord — the community is actively benchmarking OpenNext 1.0 patterns right now, and real production data is more useful than synthetic load tests.