Skip to main content
In addition to Vercel, the Node.js website can be built and deployed on the Cloudflare network using the OpenNext Cloudflare adapter. The result is a Cloudflare Worker that serves the website globally.

Build and Preview Commands

# Build and preview locally (Wrangler simulates Cloudflare hosting)
pnpm cloudflare:preview

# Build and deploy to the Cloudflare network
pnpm cloudflare:deploy
These are defined in apps/site/package.json:
{
  "cloudflare:build:worker": "OPEN_NEXT_CLOUDFLARE=true opennextjs-cloudflare build",
  "cloudflare:deploy": "opennextjs-cloudflare deploy",
  "cloudflare:preview": "wrangler dev"
}

Configuration Files

Two files control the Cloudflare deployment:

wrangler.jsonc

Cloudflare Worker settings: account ID, R2 buckets, Durable Objects, build command, module aliases.

open-next.config.ts

OpenNext Cloudflare adapter configuration. Controls how Next.js output is adapted for Cloudflare Workers.

Wrangler Configuration

The wrangler.jsonc file defines the Cloudflare Worker. Key settings:

main

Points to the Worker entry file generated by the OpenNext adapter during the build.

account_id

The Cloudflare account ID. Not required for local preview (wrangler dev), but required for deployment. Currently set to the Node.js testing account (fb4a2d0f103c6ff38854ac69eb709272).

build

Defines the build command that generates Node.js filesystem polyfills required for the application to run on Cloudflare Workers. Uses the @flarelabs/wrangler-build-time-fs-assets-polyfilling package.

alias

Maps module aliases for the Node.js filesystem polyfills generated at build time.

r2_buckets

Defines R2 bucket bindings. The site uses one R2 bucket:
{
  "r2_buckets": [
    {
      "binding": "NEXT_INC_CACHE_R2_BUCKET"
      // ... bucket configuration
    }
  ]
}
NEXT_INC_CACHE_R2_BUCKET implements the Next.js incremental cache, replacing the file-system cache that would be used in a Node.js environment.

durable_objects

Defines Durable Object bindings:
{
  "durable_objects": [
    {
      "name": "NEXT_CACHE_DO_QUEUE"
      // ... DO configuration
    }
  ]
}
NEXT_CACHE_DO_QUEUE implements the OpenNext cache queue, coordinating cache invalidation across Workers.

OpenNext Configuration

The open-next.config.ts file configures the OpenNext Cloudflare adapter. It tells the adapter how to adapt the Next.js build output to run as a Cloudflare Worker. The OPEN_NEXT_CLOUDFLARE environment variable signals to next.config.mjs that a Cloudflare build is in progress, enabling Cloudflare-specific configuration (such as the custom image loader).

Skew Protection

Vercel provides version skew protection out of the box. Cloudflare does not — the OpenNext adapter provides its own implementation. OpenNext skew protection requires three environment variables in wrangler.jsonc:
VariableDescription
CF_WORKER_NAMEName of the Worker (same as the name field in wrangler.jsonc)
CF_ACCOUNT_IDCloudflare account ID (same as account_id)
CF_PREVIEW_DOMAINPreview domain for the Worker. For Node.js this is nodejsorg
At deploy time, an additional environment variable must be set:
VariableDescription
CF_WORKERS_SCRIPTS_API_TOKENAPI token with Workers Scripts:Read permission

Custom Image Loader

When deployed on Cloudflare, Next.js’s default image optimization pipeline is not available. A custom image loader is required. The loader is at apps/site/cloudflare/image-loader.ts and is activated in next.config.mjs when the OPEN_NEXT_CLOUDFLARE environment variable is set:
// next.config.mjs
const OPEN_NEXT_CLOUDFLARE = process.env.OPEN_NEXT_CLOUDFLARE;

const nextConfig = {
  images: OPEN_NEXT_CLOUDFLARE ? getCloudflareImagesConfig() : getImagesConfig(),
};
The custom loader integrates with Cloudflare Images for image transformation and optimization.

Deployment ID (Skew Protection Mechanism)

The Cloudflare adapter requires a deploymentId to be set in the Next.js config for skew protection to work:
// next.config.mjs
const getDeploymentId = async () => {
  if (OPEN_NEXT_CLOUDFLARE) {
    const openNextAdapter = await import('@opennextjs/cloudflare');
    return openNextAdapter.getDeploymentId();
  }
  return undefined;
};

const nextConfig = {
  deploymentId: await getDeploymentId(),
};

Differences from Vercel Deployment

FeatureVercelCloudflare
Skew protectionBuilt-inRequires OpenNext implementation + env vars
Image optimizationNext.js built-inCustom Cloudflare Images loader
Incremental cacheFile system / Vercel KVR2 bucket (NEXT_INC_CACHE_R2_BUCKET)
Cache coordinationVercelDurable Objects (NEXT_CACHE_DO_QUEUE)
Install commandpnpm install --prodopennextjs-cloudflare build
Output.next/Cloudflare Worker bundle

Build docs developers (and LLMs) love