v1.0.0 to v2.0.0

219 added, 377 removed. Audit A to A.

---
name: cloudflare-nextjs
- description: "Deploy Next.js to Cloudflare Workers via OpenNext adapter. Use for SSR, ISR, App/Pages Router, or encountering worker size limits, runtime compatibility, connection scoping errors."
+ description: "Deploy Next.js to Cloudflare Workers via the OpenNext adapter (@opennextjs/cloudflare). Use for SSR/ISR/SSG/App or Pages Router, getCloudflareContext, bindings (D1/R2/KV/AI/Hyperdrive), caching tiers, skew protection, multi-worker, custom worker, env vars, or worker size/runtime/keep_names/FinalizationRegistry/connection-scoping errors."
license: MIT
metadata:
- version: 1.0.0
- last_verified: 2025-11-21
+ version: 2.0.0
+ last_verified: 2026-08-05
package_versions:
- "@opennextjs/cloudflare": "^1.13.1"
+ "@opennextjs/cloudflare": "^1.18.1"
"next": "^14.2.0 || ^15.0.0 || ^16.0.0"
"wrangler": "^4.81.0"
compatibility_requirements:
compatibility_date: "2025-05-05"
- compatibility_flags: ["nodejs_compat"]
- token_savings: "~59%"
- errors_prevented: 10
- official_docs: "https://opennext.js.org/cloudflare"
- cloudflare_guide: "https://developers.cloudflare.com/workers/framework-guides/web-apps/nextjs/"
+ compatibility_flags: ["nodejs_compat", "global_fetch_strictly_public"]
+ min_wrangler: "3.99.0"
+ token_savings: "~60%"
+ errors_prevented: 18+
+ sources:
+ overview: "https://opennext.js.org/cloudflare"
+ get_started: "https://opennext.js.org/cloudflare/get-started"
+ cli: "https://opennext.js.org/cloudflare/cli"
+ bindings: "https://opennext.js.org/cloudflare/bindings"
+ caching: "https://opennext.js.org/cloudflare/caching"
+ howto_stripe: "https://opennext.js.org/cloudflare/howtos/stripeAPI"
+ howto_db: "https://opennext.js.org/cloudflare/howtos/db"
+ howto_dev_deploy: "https://opennext.js.org/cloudflare/howtos/dev-deploy"
+ howto_env_vars: "https://opennext.js.org/cloudflare/howtos/env-vars"
+ howto_image: "https://opennext.js.org/cloudflare/howtos/image"
+ howto_custom_worker: "https://opennext.js.org/cloudflare/howtos/custom-worker"
+ howto_keep_names: "https://opennext.js.org/cloudflare/howtos/keep_names"
+ howto_workerd: "https://opennext.js.org/cloudflare/howtos/workerd"
+ howto_skew: "https://opennext.js.org/cloudflare/howtos/skew"
+ howto_assets: "https://opennext.js.org/cloudflare/howtos/assets"
+ howto_multi_worker: "https://opennext.js.org/cloudflare/howtos/multi-worker"
+ performance: "https://opennext.js.org/cloudflare/perf"
+ known_issues: "https://opennext.js.org/cloudflare/known-issues"
+ troubleshooting: "https://opennext.js.org/cloudflare/troubleshooting"
+ migration_06_to_1: "https://opennext.js.org/cloudflare/migrate-from-0.6-to-1.0.0-beta"
+ open_issues: "https://github.com/opennextjs/opennextjs-cloudflare/issues"
keywords:
- - Cloudflare Next.js
- OpenNext Cloudflare
- "@opennextjs/cloudflare"
- - Next.js Workers
+ - opennextjs-cloudflare cli
+ - Next.js on Workers
- Next.js App Router Cloudflare
- Next.js Pages Router Cloudflare
- Next.js SSR Cloudflare
- - Next.js ISR
+ - Next.js ISR Workers
- server components cloudflare
- - server actions cloudflare
+ - server actions workers
- Next.js middleware workers
- - nextjs d1
- - nextjs r2
- - nextjs kv
- - Next.js deployment
- - opennextjs-cloudflare cli
+ - getCloudflareContext
- nodejs_compat
+ - global_fetch_strictly_public
+ - workerd runtime
- worker size limit
- next.js runtime compatibility
- database connection scoping
- - Next.js migration cloudflare
+ - R2 incremental cache
+ - Durable Objects queue
+ - skew protection
+ - multi-worker
+ - custom worker
+ - keep_names
+ - FinalizationRegistry
---
- # Cloudflare Next.js Deployment Skill
- Deploy Next.js applications to Cloudflare Workers using the OpenNext Cloudflare adapter for production-ready serverless Next.js hosting.
-
- ## When to Load References
-
- Load additional reference files based on your specific task:
-
- - **`references/error-catalog-extended.md`** - Load when encountering ANY error during setup, build, or deployment. Contains complete catalog of 11+ documented issues with root causes, solutions, and official sources.
-
- - **`references/service-integration-patterns.md`** - Load when integrating Cloudflare services (D1, R2, KV, Workers AI) with Next.js. Contains complete patterns for database queries, file uploads, caching, and AI inference.
-
- - **`references/troubleshooting.md`** - Load for general troubleshooting and debugging guidance beyond the error catalog.
-
- - **`references/feature-support.md`** - Load when checking if a specific Next.js feature is supported on Cloudflare Workers (e.g., "Can I use Server Actions?", "Does ISR work?").
-
- - **`references/database-client-example.ts`** - Load when integrating external database clients (Drizzle, Prisma, PostgreSQL, MySQL) with proper request-scoping patterns required by Workers.
-
- - **`references/open-next.config.ts`** - Load when configuring caching behavior, image optimization, or custom OpenNext settings.
+ # OpenNext Cloudflare Adapter — Next.js on Workers
- - **`references/package.json`** - Load when setting up a new project or migrating an existing Next.js application to Cloudflare Workers.
+ Deploy Next.js applications to **Cloudflare Workers** using the OpenNext adapter (`@opennextjs/cloudflare`). The adapter takes a standard Next.js build, runs `package.json` build script, then transforms the output to run on the Workers runtime using the Node.js compatibility layer (`nodejs_compat`) — **not** the Edge runtime.
- - **`references/wrangler.jsonc`** - Load when configuring Worker settings, compatibility flags, environment bindings (D1, R2, KV, AI), or deployment options.
+ ## Critical Requirements (get these wrong and the build/runtime fails)
- ## Use This Skill When
+ | Requirement | Value | Why |
+ |---|---|---|
+ | Runtime | **Node.js** (default). Remove every `export const runtime = "edge";` | Edge runtime is unsupported; OpenNext uses `nodejs_compat`. |
+ | `compatibility_flags` | `["nodejs_compat", "global_fetch_strictly_public"]` | Node APIs + allow `fetch()` in app code. |
+ | `compatibility_date` | **≥ `2024-09-23`**; **≥ `2025-05-05`** recommended (FinalizationRegistry) | Older dates break `FinalizationRegistry`, DOs, and more. |
+ | Wrangler | **≥ `3.99.0`** to deploy; **≥ `4.13.0`** for `keep_names`; **≥ `4.36.0`** for stable remote bindings | Feature gates in the docs. |
+ | Next.js | v16 all minors/patches supported; latest minors of v14 and v15; **v14 dropped Q1 2026** | Stated on the overview page. |
+ | Worker size (gzip) | **3 MiB Free / 10 MiB Paid** (compressed only) | Hard Cloudflare limits. |
- - Deploying Next.js applications (App Router or Pages Router) to Cloudflare Workers
- - Need server-side rendering (SSR), static site generation (SSG), or incremental static regeneration (ISR) on Cloudflare
- - Migrating existing Next.js apps from Vercel, AWS, or other platforms to Cloudflare
- - Building full-stack Next.js applications with Cloudflare services (D1, R2, KV, Workers AI)
- - Need React Server Components, Server Actions, or Next.js middleware on Workers
- - Want global edge deployment with Cloudflare's network
+ **Windows:** not fully guaranteed (Next.js tooling issues). Use WSL, a Linux VM, or Linux/macOS CI. See known issue #1305.
- ## Key Differences from Standard Next.js
+ ## Disambiguation: this skill vs `nextjs`
- **OpenNext Adapter** transforms Next.js builds for Workers. **Critical requirements**:
- - Node.js runtime (NOT Edge) via `nodejs_compat` flag
- - Request-scoped database clients (global clients fail)
- - Worker size limits: 3 MiB (free) / 10 MiB (paid)
- - Dual testing: `next dev` for speed, `preview` for production-like validation
+ - **`nextjs` skill** → framework/App Router/Server Components/Cache Components patterns, **any platform** (Vercel, self-hosted, ...). Use for `async params`, `proxy.ts` migration, `"use cache"`.
+ - **THIS skill (`cloudflare-nextjs`)** → deploying Next.js to **Workers** via the OpenNext adapter: `wrangler.jsonc`, `open-next.config.ts`, `getCloudflareContext`, caching tiers, bindings, skew protection, multi-worker, the Workers-specific errors.
- ## Setup Patterns
+ > **proxy.ts caveat (Next 16):** Next 16 renamed `middleware.ts` → `proxy.ts`, but `@opennextjs/cloudflare` does **not** recognize `proxy.ts` yet (issue #1277) — on Cloudflare, keep using `middleware.ts`. This is the one place the `nextjs` skill's guidance does NOT apply here.
- ### New Project Setup
+ ## Quick Start
- Use Cloudflare's `create-cloudflare` (C3) CLI to scaffold a new Next.js project pre-configured for Workers:
+ ### New project (recommended)
```bash
- npm create cloudflare@latest -- my-next-app --framework=next
+ npm create cloudflare@latest -- my-next-app --framework=next --platform=workers
```
- **What this does**:
- 1. Runs Next.js official setup tool (`create-next-app`)
- 2. Installs `@opennextjs/cloudflare` adapter
- 3. Creates `wrangler.jsonc` with correct configuration
- 4. Creates `open-next.config.ts` for caching configuration
- 5. Adds deployment scripts to `package.json`
- 6. Optionally deploys immediately to Cloudflare
+ C3 scaffolds a Next.js app, installs `@opennextjs/cloudflare`, creates `wrangler.jsonc` + `open-next.config.ts` + `.dev.vars`, wires `package.json` scripts, and (if R2 is enabled) creates an R2 bucket for caching.
- **Development workflow**:
+ ### Existing Next.js project (one command)
+
```bash
- npm run dev # Next.js dev server (fast reloads)
- npm run preview # Test in workerd runtime (production-like)
- npm run deploy # Build and deploy to Cloudflare
+ npx @opennextjs/cloudflare migrate
```
- ### Existing Project Migration
-
- To add the OpenNext adapter to an existing Next.js application:
+ `migrate` automates: install adapter + wrangler, create `wrangler.jsonc`/`open-next.config.ts`/`.dev.vars`, update scripts, add `public/_headers`, add `.open-next` to `.gitignore`, wire `initOpenNextCloudflareForDev()` into `next.config.ts`, and create+configure an R2 cache bucket (only if R2 is enabled on the account).
- #### 1. Install the adapter
+ <details><summary>Manual install (if you prefer not to run migrate)</summary>
```bash
- bun add -d @opennextjs/cloudflare
+ npm install @opennextjs/cloudflare@latest
+ npm install --save-dev wrangler@latest
```
- ##### Secure Installation
-
- Adapter packages handle production traffic — pin exact versions and audit before upgrading. Follow supply chain security best practices:
-
- - **Block post-install scripts** — `npm config set ignore-scripts true` (or Bun: disabled by default)
- - **Cooldown period** — Wait 7 days for new package versions to be vetted by the community
- - **Audit before installing** — Run `socket package score npm <pkg>` or use `socket npm install <pkg>` to check packages
+ Then create the three files (see `references/wrangler.jsonc`, `references/open-next.config.ts`, `references/package.json`) and add the `dev`/`preview`/`deploy`/`upload`/`cf-typegen` scripts. **Pin adapter versions and audit before upgrading** — see the `dependency-upgrade` skill.
- Load the `dependency-upgrade` skill for full security configuration including Socket CLI integration, cooldown setup, lockfile validation, and CI enforcement.
+ </details>
- #### 2. Create wrangler.jsonc
+ ### The four scripts
```jsonc
- {
- "name": "my-next-app",
- "compatibility_date": "2025-05-05",
- "compatibility_flags": ["nodejs_compat"]
- }
- ```
-
- **Critical configuration**:
- - `compatibility_date`: **Minimum `2025-05-05`** (for FinalizationRegistry support)
- - `compatibility_flags`: **Must include `nodejs_compat`** (for Node.js runtime)
-
- #### 3. Create open-next.config.ts
-
- ```typescript
- import { defineCloudflareConfig } from "@opennextjs/cloudflare";
-
- export default defineCloudflareConfig({
- // Caching configuration (optional)
- // See: https://opennext.js.org/cloudflare/caching
- });
- ```
-
- #### 4. Update package.json scripts
-
- ```json
+ // package.json
{
- "scripts": {
- "dev": "next dev",
- "build": "next build",
- "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
- "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
- "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
- }
+ "dev": "next dev", // fast HMR via Next dev server
+ "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview", // build + run in workerd locally
+ "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy", // build + serve immediately
+ "upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload", // build + upload a version (gradual rollout)
+ "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
}
```
- **Script purposes**:
- - `dev`: Next.js development server (fast iteration)
- - `preview`: Build + run in workerd runtime (test before deploy)
- - `deploy`: Build + deploy to Cloudflare
- - `cf-typegen`: Generate TypeScript types for Cloudflare bindings
-
- #### 5. Ensure Node.js runtime (not Edge)
-
- Remove Edge runtime exports from your app:
-
- ```typescript
- // ❌ REMOVE THIS (Edge runtime not supported)
- export const runtime = "edge";
-
- // ✅ Use Node.js runtime (default)
- // No export needed - Node.js is default
- ```
-
- ## Development Workflow
+ - `dev` — fastest feedback loop; add `initOpenNextCloudflareForDev()` to `next.config.ts` so `getCloudflareContext()` works locally with simulated/remote bindings.
+ - `preview` — runs in the **actual Workers runtime** (not Node). Always run before `deploy` to catch runtime-only issues.
+ - `deploy` — populates the **remote** cache, then `wrangler deploy`. App serves immediately.
+ - `upload` — populates remote cache, then `wrangler versions upload`. Does NOT serve automatically; for gradual deployments.
- **Dual Testing Required**:
- - `npm run dev` - Fast iteration (Next.js dev server)
- - `npm run preview` - Production-like testing (workerd runtime, **REQUIRED before deploy**)
- - `npm run deploy` - Build and deploy
+ `build`, `preview`, `deploy`, `upload` all implicitly call `populateCache` — you do not need to run it manually.
- **Critical**: Always test `preview` before deploying to catch Workers-specific runtime issues
+ ### Dev `next.config.ts`
- ## Critical Configuration
+ ```ts
+ import type { NextConfig } from "next";
+ const nextConfig: NextConfig = { /* ... */ };
+ export default nextConfig;
- **wrangler.jsonc** minimum requirements:
- ```jsonc
- {
- "compatibility_date": "2025-05-05", // Minimum for FinalizationRegistry
- "compatibility_flags": ["nodejs_compat"] // Required for Node.js runtime
- }
+ import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";
+ initOpenNextCloudflareForDev();
```
- **Cloudflare Bindings**: Add D1, R2, KV, or AI bindings in `wrangler.jsonc`, access via `process.env` (see "Cloudflare Services Integration" section for complete patterns)
-
- **Package Exports** (if needed): Create `.env` with `WRANGLER_BUILD_PLATFORM="node"` to prioritize Node.js exports
-
- ## Top 5 Critical Errors
-
- These are the most common deployment-blocking errors. **For the complete catalog of 11+ errors, load `references/error-catalog-extended.md`**.
-
- ### 1. Worker Size Limit Exceeded
-
- **Error**: `"Your Worker exceeded the size limit of 3 MiB"` (Free) or `"10 MiB"` (Paid)
-
- **Quick Fix**: Upgrade plan, analyze bundle with `bunx opennextjs-cloudflare build` → check `.open-next/server-functions/default/handler.mjs.meta.json`, remove unused dependencies, or use dynamic imports.
-
- **Source**: https://opennext.js.org/cloudflare/troubleshooting#worker-size-limits
-
- ---
-
- ### 2. Cannot Perform I/O on Behalf of Different Request
-
- **Error**: `"Cannot perform I/O on behalf of a different request"`
-
- **Cause**: Global database client reused across requests (Workers limitation)
+ ## Accessing Cloudflare Bindings — `getCloudflareContext()`
- **Quick Fix**: Create database clients INSIDE request handlers, never globally. Or use Cloudflare D1 which is designed for Workers.
+ **Do NOT use `process.env` for bindings.** The official API is `getCloudflareContext()` from `@opennextjs/cloudflare`.
- ```typescript
- // ❌ WRONG: Global client
- const pool = new Pool({ connectionString: process.env.DATABASE_URL });
+ ```ts
+ import { getCloudflareContext } from "@opennextjs/cloudflare";
- // ✅ CORRECT: Request-scoped
export async function GET() {
- const pool = new Pool({ connectionString: process.env.DATABASE_URL });
- // ... use pool
- await pool.end();
+ const { env, cf, ctx } = getCloudflareContext();
+ await env.MY_KV.put("foo", "bar");
+ return new Response(await env.MY_KV.get("foo"));
}
```
- **Source**: https://opennext.js.org/cloudflare/troubleshooting#cannot-perform-io-on-behalf-of-a-different-request
-
- ---
-
- ### 3. NPM Package Import Failures
-
- **Error**: `"Could not resolve '<package>'"`
-
- **Quick Fix**: Enable `nodejs_compat` flag in wrangler.jsonc, and/or create `.env` with `WRANGLER_BUILD_PLATFORM="node"`.
-
- **Source**: https://opennext.js.org/cloudflare/troubleshooting#npm-packages-fail-to-import
-
- ---
-
- ### 4. SSRF Vulnerability (CVE-2025-6087)
-
- **Vulnerability**: Server-Side Request Forgery via `/_next/image` endpoint in versions < 1.3.0
-
- **Quick Fix**: Upgrade immediately: `bun add -d @opennextjs/cloudflare@^1.3.0`
-
- **Source**: https://github.com/advisories/GHSA-rvpw-p7vw-wj3m
-
- ---
-
- ### 5. Failed to Load Chunk (Turbopack)
-
- **Error**: `"Failed to load chunk server/chunks/ssr/"`
-
- **Quick Fix**: Remove `--turbo` flag from build command. Use `next build` (standard), NOT `next build --turbo`.
-
- **Source**: https://opennext.js.org/cloudflare/troubleshooting#failed-to-load-chunk
-
- ---
-
- **More Errors**: Load `references/error-catalog-extended.md` for 6 additional documented errors including FinalizationRegistry issues, Durable Objects warnings, Prisma conflicts, cross-fetch errors, and Windows development issues
-
- ## Feature Support Matrix
-
- | Feature | Status | Notes |
- |---------|--------|-------|
- | **App Router** | ✅ Fully Supported | Latest App Router features work |
- | **Pages Router** | ✅ Fully Supported | Legacy Pages Router supported |
- | **Route Handlers** | ✅ Fully Supported | API routes work as expected |
- | **React Server Components** | ✅ Fully Supported | RSC fully functional |
- | **Server Actions** | ✅ Fully Supported | Server Actions work |
- | **SSG** | ✅ Fully Supported | Static Site Generation |
- | **SSR** | ✅ Fully Supported | Server-Side Rendering |
- | **ISR** | ✅ Fully Supported | Incremental Static Regeneration |
- | **Middleware** | ✅ Supported | Except Node.js middleware (15.2+) |
- | **Image Optimization** | ✅ Supported | Via Cloudflare Images |
- | **Partial Prerendering (PPR)** | ✅ Supported | Experimental in Next.js |
- | **Composable Caching** | ✅ Supported | `'use cache'` directive |
- | **Response Streaming** | ✅ Supported | Streaming responses work |
- | **`next/after` API** | ✅ Supported | Post-response async work |
- | **Node.js Middleware (15.2+)** | ❌ Not Supported | Future support planned |
- | **Edge Runtime** | ❌ Not Supported | Use Node.js runtime |
-
- **Source**: https://developers.cloudflare.com/workers/framework-guides/web-apps/nextjs/#next-js-supported-features
-
- ## Cloudflare Services Integration
-
- Access Cloudflare bindings via `process.env` in Next.js route handlers:
-
- ```typescript
- import type { NextRequest } from 'next/server';
-
- export async function GET(request: NextRequest) {
- const env = process.env as any;
-
- // D1 Database
- const users = await env.DB.prepare('SELECT * FROM users').all();
-
- // R2 Storage
- const file = await env.BUCKET.get('file.txt');
-
- // KV Storage
- const value = await env.KV.get('key');
-
- // Workers AI
- const ai = await env.AI.run('@cf/meta/llama-3-8b-instruct', { prompt: 'Hello' });
-
- return Response.json({ users, file, value, ai });
- }
- ```
+ **Static routes (ISR/SSG) MUST use async mode** — and be careful: secrets/local values are used during static generation.
- **Wrangler Bindings Configuration**:
- ```jsonc
- {
- "d1_databases": [{ "binding": "DB", "database_id": "..." }],
- "r2_buckets": [{ "binding": "BUCKET", "bucket_name": "..." }],
- "kv_namespaces": [{ "binding": "KV", "id": "..." }],
- "ai": { "binding": "AI" }
- }
+ ```ts
+ const { env } = await getCloudflareContext({ async: true });
```
- **Detailed Integration Patterns**: Load `references/service-integration-patterns.md` for complete patterns including:
- - D1: Queries, inserts, transactions, batch operations
- - R2: Upload, download, list, delete with streaming
- - KV: Get, set with TTL, delete, list keys
- - Workers AI: Text generation, embeddings, image classification
- - Multi-service integration examples
- - TypeScript types for bindings (`npm run cf-typegen`)
-
- **Related Skills**: `cloudflare-d1`, `cloudflare-r2`, `cloudflare-kv`, `cloudflare-workers-ai` for service-specific deep dives
-
- ## Image Optimization & Caching
-
- **Images**: Automatic optimization via Cloudflare Images (billed separately). Configure in `open-next.config.ts` with `imageOptimization: { loader: 'cloudflare' }`. Use standard Next.js `<Image />` component.
-
- **Caching**: OpenNext provides sensible defaults. Override in `open-next.config.ts` if needed. See https://opennext.js.org/cloudflare/caching for advanced configuration
-
- ## Known Limitations
-
- ### Not Yet Supported
-
- 1. **Node.js Middleware (Next.js 15.2+)**
- - Introduced in Next.js 15.2
- - Support planned for future releases
- - Use standard middleware for now
-
- 2. **Edge Runtime**
- - Only Node.js runtime supported
- - Remove `export const runtime = "edge"` from your app
+ **TypeScript types:** `npm run cf-typegen` generates `cloudflare-env.d.ts` (re-run after any binding change).
- 3. **Full Windows Support**
- - Development on Windows not fully guaranteed
- - Use WSL, VM, or Linux-based CI/CD
+ **Remote bindings (local dev → real resources):** stabilized in **Wrangler 4.36.0**. On older wrangler, enable via `initOpenNextCloudflareForDev({ experimental: { remoteBindings: true } })` and use the `experimental_remote` (not `remote`) key on binding options. Note: remote bindings are also used **during build**.
- ### Worker Size Constraints
+ Full patterns (D1/R2/KV/AI/Hyperdrive, Drizzle, Prisma, Stripe) → `references/bindings-and-services.md`.
- - **Free plan**: 3 MiB limit (gzip-compressed)
- - **Paid plan**: 10 MiB limit (gzip-compressed)
- - Monitor bundle size during development
- - Use dynamic imports for code splitting
+ ## Caching — three components, three tiers
- ### Database Connections
+ OpenNext's cache has three parts: **Incremental Cache** (storage), **Queue** (dedupe/revalidate), **Tag Cache** (on-demand `revalidateTag`/`revalidatePath`).
- - External database clients (PostgreSQL, MySQL) must be request-scoped
- - Cannot reuse connections across requests (Workers limitation)
- - Prefer Cloudflare D1 for database needs (designed for Workers)
+ | Site profile | Incremental | Queue | Tag Cache | When |
+ |---|---|---|---|---|
+ | **SSG only** (no revalidation) | `staticAssetsIncrementalCache` + `enableCacheInterception: true` | none | none | Fastest option; read-only |
+ | **Small site** (ISR/on-demand) | `r2IncrementalCache` | `doQueue` | `d1NextTagCache` | Low traffic; D1 tag cache |
+ | **Large/high-traffic site** | `withRegionalCache(r2IncrementalCache, { mode: "long-lived" })` | `doQueue` | `doShardedTagCache({ baseShardSize: 12 })` + `purgeCache({ type: "direct" })` | DO-sharded; add cache purge if using on-demand |
- ## Deployment
+ **Reserved binding names** (do not reuse): `ASSETS`, `WORKER_SELF_REFERENCE`, `NEXT_INC_CACHE_R2_BUCKET`, `NEXT_CACHE_DO_QUEUE`, `NEXT_TAG_CACHE_D1`, `NEXT_TAG_CACHE_DO_SHARDED`, `NEXT_CACHE_DO_PURGE`, `IMAGES`.
- **Local**: `npm run deploy` (builds and deploys)
+ - **Avoid Workers KV** for incremental cache — eventually consistent, can persist stale data indefinitely.
+ - **Cache interception + PPR**: incompatible today; cache interception is NOT enabled by default and does not work with PPR.
+ - **On-demand revalidation** requires both a Tag Cache **and** the Cache Purge component (cache purge only works on a zone/custom domain; needs `CACHE_PURGE_API_TOKEN` + `CACHE_PURGE_ZONE_ID` secrets).
+ - **Pages Router** `res.revalidate` requires a self-reference service binding named `WORKER_SELF_REFERENCE`.
+ - **Headers caveat**: the Worker does not run in front of static assets, so `next.config.ts` `headers()` for `public/` and immutable build files do not apply. Use `public/_headers`.
- **CI/CD**: Use `npm run deploy` command in GitHub Actions, GitLab CI, or Cloudflare Workers Builds (auto-detected)
+ Deep dive (all options, env vars, regional modes, migration from 0.6) → `references/caching.md` and `references/known-issues.md`.
- **Custom Domains**: Workers & Pages → Settings → Domains & Routes (domain must be on Cloudflare)
+ ## Common Integrations (condensed — full patterns in references)
- ## TypeScript & Testing
+ - **Drizzle + D1/Hyperdrive/PG**, **Prisma + D1/PG/Hyperdrive** — request-scoped clients via `cache()` from `react`; `maxUses: 1` on PG pools; `getCloudflareContext({ async: true })` for ISR/SSG; Prisma needs `previewFeatures = ["driverAdapters"]`, no output dir in `schema.prisma`, and `serverExternalPackages: ["@prisma/client", ".prisma/client"]`. → `references/bindings-and-services.md`
+ - **Stripe** — Workers have no `node:https`; pass `httpClient: Stripe.createFetchHttpClient()`. → `references/bindings-and-services.md`
+ - **Image optimization** — `images.binding: "IMAGES"` in `wrangler.jsonc`, **or** a custom loader (`/cdn-cgi/image/...`) for zones. `minimumCacheTTL` and `dangerouslyAllowLocalIP` are not supported; custom loader bypasses middleware and ignores `remotePatterns`. → `references/advanced.md`
+ - **Env vars** — use Next.js `.env` files (not just `.dev.vars`); `NEXTJS_ENV` in `.dev.vars` selects the env; `--keep-vars` on deploy; secrets are write-only. → `references/dev-deploy-and-env.md`
+ - **Custom worker** (add `scheduled`, Durable Object exports) — point `main` at your worker that re-exports the generated fetch handler. → `references/advanced.md`
+ - **Multi-worker** (split middleware from server) — reduces per-worker memory + cold starts; **incompatible** with preview URLs, skew protection, and `@opennextjs/cloudflare deploy`. → `references/advanced.md`
+ - **Skew protection** (preview-URL-based version matching) — `cloudflare.skewProtection.enabled`, `run_worker_first: true`, `getDeploymentId()`, env vars `CF_WORKER_NAME`/`CF_PREVIEW_DOMAIN`/`CF_WORKERS_SCRIPTS_API_TOKEN`/`CF_ACCOUNT_ID`. **Disabled for Workers with a Durable Object** (move DOs to a separate worker). → `references/advanced.md`
- **TypeScript Types**: Run `npm run cf-typegen` to generate `cloudflare-env.d.ts` with typed bindings (D1Database, R2Bucket, KVNamespace, Ai)
+ ## Top Errors (full catalog → `references/error-catalog-extended.md`)
- **Testing**: Always test in `preview` mode before deployment to catch Workers-specific runtime issues and verify bindings work correctly
+ ### 1. Worker size limit exceeded
+ `"Your Worker exceeded the size limit of 3 MiB"` (Free) / `"10 MiB"` (Paid). Only **gzip** size counts. Free → upgrade to Paid. Paid → analyze bundle: `npx @opennextjs/cloudflare build`, then inspect `.open-next/server-functions/default/handler.mjs.meta.json` (visualize with ESBuild Bundle Analyzer); remove unused deps, use dynamic imports.
- ## Migration from Other Platforms
+ ### 2. Cannot perform I/O on behalf of a different request
+ Global DB client (e.g. `postgres`, `pg` Pool) reused across requests. Create the client **inside** the request handler (or use `cache()` from `react`), and `maxUses: 1` for PG pools.
- ### From Vercel
+ ### 3. NPM package import / "Could not resolve \<package\>"
+ Enable `nodejs_compat`, ensure `compatibility_date ≥ 2024-09-23`. Some packages ship a `workerd` export — add them to `serverExternalPackages` in `next.config.ts` (e.g. `@prisma/client`, `.prisma/client`, `postgres`, `jose`, `react-textarea-autosize`, `@libsql/isomorphic-ws`). Or set `.env`: `WRANGLER_BUILD_CONDITIONS=""` + `WRANGLER_BUILD_PLATFORM="node"`.
- 1. Copy existing Next.js project
- 2. Run existing project migration steps (above)
- 3. Update environment variables in Cloudflare dashboard
- 4. Replace Vercel-specific features:
- - Vercel Postgres → Cloudflare D1
- - Vercel Blob → Cloudflare R2
- - Vercel KV → Cloudflare KV
- - Vercel Edge Config → Cloudflare KV
- 5. Test thoroughly with `npm run preview`
- 6. Deploy with `npm run deploy`
+ ### 4. SSRF (CVE-2025-6087) — versions < 1.3.0
+ `/_next/image` SSRF. Upgrade immediately: `@opennextjs/cloudflare@^1.3.0` (current: `^1.18.1`).
- ### From AWS / Other Platforms
+ ### 5. Failed to load chunk `server/chunks/ssr/<name>.js`
+ Outdated adapter with Turbopack builds. Upgrade `@opennextjs/cloudflare` to latest, or switch to webpack (`next build` without `--turbo`).
- Same process as Vercel migration - the adapter handles Next.js standard features automatically.
+ ### 6. `ReferenceError: FinalizationRegistry is not defined`
+ `compatibility_date` too old. Set `"compatibility_date": "2025-05-05"` (or later) in `wrangler.jsonc`.
- ## Resources
+ ### 7. `Uncaught ReferenceError: __name is not defined`
+ Wrangler's esbuild `keep-names` injects `__name` into generated script strings that some libs (e.g. `next-themes`) eval at runtime. Set `"keep_names": false` in `wrangler.jsonc` (requires **Wrangler ≥ 4.13.0**). You lose original function names in debugging.
- ### Official Documentation
- - **OpenNext Cloudflare**: https://opennext.js.org/cloudflare
- - **Cloudflare Next.js Guide**: https://developers.cloudflare.com/workers/framework-guides/web-apps/nextjs/
- - **Next.js Docs**: https://nextjs.org/docs
+ ### 8. "Failed to send request to R2 worker" / 403 during `populateCache remote`
+ Account protected by Cloudflare Access blocks the `open-next-cache-populate` helper worker. Do **not** create a separate Access app for it; add a Service Auth policy (Include = Any Access Service Token) to the existing app covering `*.<account>.workers.dev`, create a service token, and export `CLOUDFLARE_ACCESS_CLIENT_ID` / `CLOUDFLARE_ACCESS_CLIENT_SECRET`.
- ### Troubleshooting
- - **Troubleshooting Guide**: https://opennext.js.org/cloudflare/troubleshooting
- - **Known Issues**: https://opennext.js.org/cloudflare/known-issues
- - **GitHub Issues**: https://github.com/opennextjs/opennextjs-cloudflare/issues
+ ## Known Open Bugs (live tracker)
- ### Related Skills
- - `cloudflare-worker-base` - Base Worker setup with Hono + Vite + React
- - `cloudflare-d1` - D1 database integration
- - `cloudflare-r2` - R2 object storage
- - `cloudflare-kv` - KV key-value storage
- - `cloudflare-workers-ai` - Workers AI integration
- - `cloudflare-vectorize` - Vector database for RAG
+ Always check the issue tracker — these are recurring at the time of writing:
- ## Quick Reference
+ | # | Bug | Workaround |
+ |---|---|---|
+ | [#1171](https://github.com/opennextjs/opennextjs-cloudflare/issues/1171) | **v1.18.0 breaks R2 cache population** (pinned) | Pin to 1.17.x or upgrade past the fix |
+ | [#1277](https://github.com/opennextjs/opennextjs-cloudflare/issues/1277) | **`proxy.js` not supported** — Next 16 `proxy.ts` rename breaks routing | Keep `middleware.ts` on Cloudflare |
+ | [#1130](https://github.com/opennextjs/opennextjs-cloudflare/issues/1130) / [#1225](https://github.com/opennextjs/opennextjs-cloudflare/issues/1225) | `cacheComponents: true` crashes (`Unexpected identifier '$'` / `Connection closed`) | Disable `cacheComponents` |
+ | [#1321](https://github.com/opennextjs/opennextjs-cloudflare/issues/1321) | Intermittent React hydration mismatch (~9% of loads) | — |
+ | [#1322](https://github.com/opennextjs/opennextjs-cloudflare/issues/1322) / [#1214](https://github.com/opennextjs/opennextjs-cloudflare/issues/1214) | Hyperdrive + `pg` / `@prisma/adapter-pg` bundling failure | — |
+ | [#1315](https://github.com/opennextjs/opennextjs-cloudflare/issues/1315) | Time-based fetch-cache revalidation silently no-ops on Next 16 (deployed) | — |
+ | [#1305](https://github.com/opennextjs/opennextjs-cloudflare/issues/1305) | Windows + Turbopack routes 500 | Use Linux/macOS or webpack |
+ | [#1317](https://github.com/opennextjs/opennextjs-cloudflare/issues/1317) | `@cf-wasm/photon` Turbopack build fails (raw `.wasm`) | Use webpack |
+ | [#1326](https://github.com/opennextjs/opennextjs-cloudflare/issues/1326) | Webpack chunk inlining misses named chunks → `Unknown chunk N` | — |
+ | [#617](https://github.com/opennextjs/opennextjs-cloudflare/issues/617) | Node middleware (Next 15.2+) unsupported (feature request) | Use standard middleware |
- ### Essential Commands
+ Full tracker: https://github.com/opennextjs/opennextjs-cloudflare/issues
- ```bash
- # New project
- npm create cloudflare@latest -- my-next-app --framework=next
+ ## Feature Support
- # Development
- npm run dev # Fast iteration (Next.js dev server)
- npm run preview # Test in workerd (production-like)
+ | Feature | Status | Notes |
+ |---|---|---|
+ | App Router, Pages Router, Route Handlers, Dynamic routes | ✅ | Full |
+ | React Server Components, Server Actions | ✅ | Full |
+ | SSG, SSR, ISR | ✅ | Full |
+ | Middleware | ✅ | **Except** Node middleware (Next 15.2+, issue #617) |
+ | Image optimization | ✅ | Via Cloudflare Images (binding or custom loader) |
+ | Partial Prerendering (PPR) | ✅ | But cache interception + PPR incompatible today |
+ | Composable Caching (`'use cache'`), `after` | ✅ | |
+ | Turbopack | ✅ | But see #1305, #1317, #1326 — webpack is safer |
+ | Edge Runtime | ❌ | Node runtime only; remove `runtime = "edge"` |
+ | Node Middleware (15.2+) | ❌ | #617 |
- # Deployment
- npm run deploy # Build and deploy to Cloudflare
+ ## Related Skills
- # TypeScript
- npm run cf-typegen # Generate binding types
- ```
+ | Skill | Use for |
+ |---|---|
+ | `nextjs` | Next.js framework/App Router patterns on any platform (the `proxy.ts`/cache/Server Components reference) |
+ | `cloudflare-workers` | Generic Workers patterns; framework decision tree (Hono vs OpenNext) |
+ | `drizzle-orm-d1` | Drizzle + D1 deep dive (note: OpenNext must not bundle Wrangler — see its error catalog) |
+ | `cloudflare-r2` / `cloudflare-kv` / `cloudflare-d1` | Service-specific deep dives |
+ | `dependency-upgrade` | Pinning/auditing `@opennextjs/cloudflare` (production traffic) |
- ### Critical Configuration
+ ## When to Load References
- ```jsonc
- // wrangler.jsonc
- {
- "compatibility_date": "2025-05-05", // Minimum!
- "compatibility_flags": ["nodejs_compat"] // Required!
- }
- ```
+ | File | Load when |
+ |---|---|
+ | `references/caching.md` | Choosing/configuring incremental/queue/tag cache, regional cache, cache purge |
+ | `references/bindings-and-services.md` | Integrating D1/R2/KV/AI/Hyperdrive, Drizzle/Prisma request-scoped clients, Stripe |
+ | `references/dev-deploy-and-env.md` | Setting up dev/preview/deploy, Workers Builds CI, env vars/secrets |
+ | `references/advanced.md` | Custom worker, multi-worker, skew protection, static assets, keep_names, workerd packages, image optimization |
+ | `references/known-issues.md` | DO build warnings, migrating 0.6 → 1.0.0-beta |
+ | `references/error-catalog-extended.md` | Any error beyond the top 8 above |
+ | `references/troubleshooting.md` | Step-by-step debugging + profiling/minification |
+ | `references/feature-support.md` | Detailed feature compatibility matrix |
+ | `references/wrangler.jsonc` | Small-site and large-site wrangler templates (all reserved bindings) |
+ | `references/open-next.config.ts` | The three caching tiers as runnable configs |
+ | `references/database-client-example.ts` | Request-scoped DB client patterns |
+ | `references/package.json` | Reference scripts + versions |
- ### Common Pitfalls
+ ## Sources
- 1. ❌ Using Edge runtime → ✅ Use Node.js runtime
- 2. ❌ Global DB clients → ✅ Request-scoped clients
- 3. ❌ Old compatibility_date → ✅ Use 2025-05-05+
- 4. ❌ Missing nodejs_compat → ✅ Add to compatibility_flags
- 5. ❌ Only testing in `dev` → ✅ Always test `preview` before deploy
- 6. ❌ Using Turbopack → ✅ Use standard Next.js build
+ - Overview — https://opennext.js.org/cloudflare
+ - Get started — https://opennext.js.org/cloudflare/get-started
+ - CLI — https://opennext.js.org/cloudflare/cli
+ - Bindings — https://opennext.js.org/cloudflare/bindings
+ - Caching — https://opennext.js.org/cloudflare/caching
+ - How-to: Stripe — https://opennext.js.org/cloudflare/howtos/stripeAPI
+ - How-to: DB — https://opennext.js.org/cloudflare/howtos/db
+ - How-to: Dev/deploy — https://opennext.js.org/cloudflare/howtos/dev-deploy
+ - How-to: Env vars — https://opennext.js.org/cloudflare/howtos/env-vars
+ - How-to: Image — https://opennext.js.org/cloudflare/howtos/image
+ - How-to: Custom worker — https://opennext.js.org/cloudflare/howtos/custom-worker
+ - How-to: keep_names — https://opennext.js.org/cloudflare/howtos/keep_names
+ - How-to: workerd — https://opennext.js.org/cloudflare/howtos/workerd
+ - How-to: Skew protection — https://opennext.js.org/cloudflare/howtos/skew
+ - How-to: Assets — https://opennext.js.org/cloudflare/howtos/assets
+ - How-to: Multi-worker — https://opennext.js.org/cloudflare/howtos/multi-worker
+ - Performance — https://opennext.js.org/cloudflare/perf
+ - Known issues — https://opennext.js.org/cloudflare/known-issues
+ - Troubleshooting — https://opennext.js.org/cloudflare/troubleshooting
+ - Migration 0.6 → 1.0.0-beta — https://opennext.js.org/cloudflare/migrate-from-0.6-to-1.0.0-beta
+ - Open issues — https://github.com/opennextjs/opennextjs-cloudflare/issues
---
-
- **Production Tested**: Official Cloudflare support and active community
- **Token Savings**: ~59% vs manual setup
- **Errors Prevented**: 11+ documented issues
- **Last Verified**: 2025-12-04
+ **Version**: `@opennextjs/cloudflare ^1.18.1` · Next.js 14/15/16 · Wrangler ≥ 3.99.0 · `compatibility_date ≥ 2025-05-05`
+ **Last Verified**: 2026-08-05