xiaohongshu
xiaohongshu
cloudflare-nextjs
Deploy Next.js applications (App Router and Pages Router) to Cloudflare Workers using the OpenNext adapter. This skill should be used when deploying Next.js apps with SSR, ISR, or server components to Cloudflare's serverless platform. It covers setup for both new and existing projects, configurat...
Full skill instructions
Deploy Next.js applications to Cloudflare Workers using the OpenNext Cloudflare adapter for production-ready serverless Next.js hosting.
The OpenNext Cloudflare adapter (@opennextjs/cloudflare) transforms Next.js build output into Cloudflare Worker-compatible format. This is fundamentally different from standard Next.js deployments:
next build → OpenNext transformation → Worker deployment| Aspect | Standard Next.js | Cloudflare Workers |
|---|---|---|
| Runtime | Node.js or Edge | Node.js (via nodejs_compat) |
| Dev Server | next dev | next dev + opennextjs-cloudflare preview |
| Deployment | Platform-specific | opennextjs-cloudflare deploy |
| Worker Size | No limit | 3 MiB (free) / 10 MiB (paid) |
| Database Connections | Global clients OK | Must be request-scoped |
| Image Optimization | Built-in | Via Cloudflare Images |
| Caching | Next.js cache | OpenNext config + Workers cache |
Use Cloudflare's create-cloudflare (C3) CLI to scaffold a new Next.js project pre-configured for Workers:
npm create cloudflare@latest -- my-next-app --framework=next
What this does:
create-next-app)@opennextjs/cloudflare adapterwrangler.jsonc with correct configurationopen-next.config.ts for caching configurationpackage.jsonDevelopment workflow:
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
To add the OpenNext adapter to an existing Next.js application:
npm install --save-dev @opennextjs/cloudflare
{
"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)import { defineCloudflareConfig } from "@opennextjs/cloudflare";
export default defineCloudflareConfig({
// Caching configuration (optional)
// See: https://opennext.js.org/cloudflare/caching
});
{
"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"
}
}
Script purposes:
dev: Next.js development server (fast iteration)preview: Build + run in workerd runtime (test before deploy)deploy: Build + deploy to Cloudflarecf-typegen: Generate TypeScript types for Cloudflare bindingsRemove Edge runtime exports from your app:
// ❌ REMOVE THIS (Edge runtime not supported)
export const runtime = "edge";
// ✅ Use Node.js runtime (default)
// No export needed - Node.js is default
Always test in BOTH environments:
Next.js Dev Server (npm run dev)
Workerd Runtime (npm run preview)
# Iterating on UI/logic → Use Next.js dev server
npm run dev
# Testing integrations (D1, R2, KV) → Use preview
npm run preview
# Before deploying → ALWAYS test preview
npm run preview
# Deploy to production
npm run deploy
Minimum requirements in wrangler.jsonc:
{
"name": "your-app-name",
"compatibility_date": "2025-05-05", // Minimum for FinalizationRegistry
"compatibility_flags": ["nodejs_compat"] // Required for Node.js runtime
}
If using npm packages with multiple export conditions, create .env:
WRANGLER_BUILD_CONDITIONS=""
WRANGLER_BUILD_PLATFORM="node"
This ensures Wrangler prioritizes the node export when available.
Add bindings in wrangler.jsonc:
{
"name": "your-app-name",
"compatibility_date": "2025-05-05",
"compatibility_flags": ["nodejs_compat"],
// D1 Database
"d1_databases": [
{
"binding": "DB",
"database_name": "production-db",
"database_id": "your-database-id"
}
],
// R2 Storage
"r2_buckets": [
{
"binding": "BUCKET",
"bucket_name": "your-bucket"
}
],
// KV Storage
"kv_namespaces": [
{
"binding": "KV",
"id": "your-kv-id"
}
],
// Workers AI
"ai": {
"binding": "AI"
}
}
Access bindings in Next.js via process.env:
// app/api/route.ts
import type { NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
// Access Cloudflare bindings
const env = process.env as any;
// D1 Database query
const result = await env.DB.prepare('SELECT * FROM users').all();
// R2 Storage access
const file = await env.BUCKET.get('file.txt');
// KV Storage access
const value = await env.KV.get('key');
// Workers AI inference
const response = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
prompt: 'Hello AI'
});
return Response.json({ result });
}
Error: "Your Worker exceeded the size limit of 3 MiB"
Cause: Workers Free plan limits Worker size to 3 MiB (gzip-compressed)
Solutions:
Bundle analysis:
npx opennextjs-cloudflare build
cd .open-next/server-functions/default
# Analyze handler.mjs.meta.json with ESBuild Bundle Analyzer
Source: https://opennext.js.org/cloudflare/troubleshooting#worker-size-limits
Error: "Your Worker exceeded the size limit of 10 MiB"
Cause: Unnecessary code bundled into Worker
Debug workflow:
npx opennextjs-cloudflare build.open-next/server-functions/defaulthandler.mjs.meta.json using ESBuild Bundle AnalyzerSource: https://opennext.js.org/cloudflare/troubleshooting#worker-size-limits
Error: "ReferenceError: FinalizationRegistry is not defined"
Cause: compatibility_date in wrangler.jsonc is too old
Solution: Update compatibility_date to 2025-05-05 or later:
{
"compatibility_date": "2025-05-05" // Minimum for FinalizationRegistry
}
Source: https://opennext.js.org/cloudflare/troubleshooting#finalizationregistry-is-not-defined
Error: "Cannot perform I/O on behalf of a different request"
Cause: Database client created globally and reused across requests
Problem code:
// ❌ WRONG: Global DB client
import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export async function GET() {
// This will fail - pool created in different request context
const result = await pool.query('SELECT * FROM users');
return Response.json(result);
}
Solution: Create database clients inside request handlers:
// ✅ CORRECT: Request-scoped DB client
import { Pool } from 'pg';
export async function GET() {
// Create client within request context
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const result = await pool.query('SELECT * FROM users');
await pool.end();
return Response.json(result);
}
Alternative: Use Cloudflare D1 (designed for Workers) instead of external databases:
// ✅ BEST: Use D1 (no connection pooling needed)
export async function GET(request: NextRequest) {
const env = process.env as any;
const result = await env.DB.prepare('SELECT * FROM users').all();
return Response.json(result);
}
Error: "Could not resolve '<package>'"
Cause: Missing nodejs_compat flag or package export conditions
Solution 1: Enable nodejs_compat flag:
{
"compatibility_flags": ["nodejs_compat"]
}
Solution 2: For packages with multiple exports, create .env:
WRANGLER_BUILD_CONDITIONS=""
WRANGLER_BUILD_PLATFORM="node"
Source: https://opennext.js.org/cloudflare/troubleshooting#npm-packages-fail-to-import
Error: "Failed to load chunk server/chunks/ssr/"
Cause: Next.js built with Turbopack (next build --turbo)
Solution: Use standard build (Turbopack not supported by adapter):
{
"scripts": {
"build": "next build" // ✅ Correct
// "build": "next build --turbo" // ❌ Don't use Turbopack
}
}
Source: https://opennext.js.org/cloudflare/troubleshooting#failed-to-load-chunk
Vulnerability: Server-Side Request Forgery via /_next/image endpoint
Affected versions: @opennextjs/cloudflare < 1.3.0
Solution: Upgrade to version 1.3.0 or later:
npm install --save-dev @opennextjs/cloudflare@^1.3.0
Impact: Allows unauthenticated users to proxy arbitrary remote content
Source: https://github.com/advisories/GHSA-rvpw-p7vw-wj3m
Warning: "You have defined bindings to the following internal Durable Objects... will not work in local development, but they should work in production"
Cause: OpenNext uses Durable Objects for caching (DOQueueHandler, DOShardedTagCache)
Solution: Safe to ignore - warning is expected behavior
Alternative (to suppress warning): Define Durable Objects in separate Worker with own config
Source: https://opennext.js.org/cloudflare/known-issues#caching-durable-objects
Error: Build errors when using @prisma/client + @prisma/adapter-d1 in Next.js middleware
Cause: Database initialization in middleware context
Workaround: Initialize Prisma client in route handlers, not middleware
Source: https://github.com/opennextjs/opennextjs-cloudflare/issues/471
Error: Errors when using libraries that depend on cross-fetch
Cause: OpenNext patches deployment package causing cross-fetch to try using Node.js libraries when native fetch is available
Solution: Use native fetch API directly instead of cross-fetch:
// ✅ Use native fetch
const response = await fetch('https://api.example.com/data');
// ❌ Avoid cross-fetch
// import fetch from 'cross-fetch';
Source: https://opennext.js.org/cloudflare/troubleshooting
Issue: Full Windows support not guaranteed
Cause: Underlying Next.js tooling issues on Windows
Solutions:
Source: https://opennext.js.org/cloudflare#windows-support
| 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 |
// app/api/users/route.ts
import type { NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
const env = process.env as any;
const result = await env.DB.prepare(
'SELECT * FROM users WHERE active = ?'
).bind(true).all();
return Response.json(result.results);
}
export async function POST(request: NextRequest) {
const env = process.env as any;
const { name, email } = await request.json();
const result = await env.DB.prepare(
'INSERT INTO users (name, email) VALUES (?, ?)'
).bind(name, email).run();
return Response.json({ id: result.meta.last_row_id });
}
Wrangler config:
{
"d1_databases": [
{
"binding": "DB",
"database_name": "production-db",
"database_id": "your-database-id"
}
]
}
See also: cloudflare-d1 skill for complete D1 patterns
// app/api/upload/route.ts
import type { NextRequest } from 'next/server';
export async function POST(request: NextRequest) {
const env = process.env as any;
const formData = await request.formData();
const file = formData.get('file') as File;
// Upload to R2
await env.BUCKET.put(file.name, file.stream(), {
httpMetadata: {
contentType: file.type
}
});
return Response.json({ success: true, filename: file.name });
}
export async function GET(request: NextRequest) {
const env = process.env as any;
const { searchParams } = new URL(request.url);
const filename = searchParams.get('file');
const object = await env.BUCKET.get(filename);
if (!object) {
return new Response('Not found', { status: 404 });
}
return new Response(object.body, {
headers: {
'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream'
}
});
}
See also: cloudflare-r2 skill for complete R2 patterns
// app/api/ai/route.ts
import type { NextRequest } from 'next/server';
export async function POST(request: NextRequest) {
const env = process.env as any;
const { prompt } = await request.json();
const response = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
prompt
});
return Response.json(response);
}
Wrangler config:
{
"ai": {
"binding": "AI"
}
}
See also: cloudflare-workers-ai skill for complete AI patterns
// app/api/cache/route.ts
import type { NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
const env = process.env as any;
const { searchParams } = new URL(request.url);
const key = searchParams.get('key');
const value = await env.KV.get(key);
return Response.json({ key, value });
}
export async function PUT(request: NextRequest) {
const env = process.env as any;
const { key, value, ttl } = await request.json();
await env.KV.put(key, value, { expirationTtl: ttl });
return Response.json({ success: true });
}
See also: cloudflare-kv skill for complete KV patterns
Next.js image optimization works via Cloudflare Images. Configure in open-next.config.ts:
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
export default defineCloudflareConfig({
imageOptimization: {
loader: 'cloudflare'
}
});
Usage in components:
import Image from 'next/image';
export default function Avatar() {
return (
<Image
src="/avatar.jpg"
alt="User avatar"
width={200}
height={200}
// Automatically optimized via Cloudflare Images
/>
);
}
Billing: Cloudflare Images usage is billed separately
Docs: https://developers.cloudflare.com/images/
Configure caching behavior in open-next.config.ts:
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
export default defineCloudflareConfig({
// Custom cache configuration
cache: {
// Override default cache behavior
// See: https://opennext.js.org/cloudflare/caching
}
});
Default behavior: OpenNext provides sensible caching defaults
Advanced usage: See official OpenNext caching documentation
Node.js Middleware (Next.js 15.2+)
Edge Runtime
export const runtime = "edge" from your appFull Windows Support
# Build and deploy in one command
npm run deploy
# Or step by step:
npx opennextjs-cloudflare build
npx opennextjs-cloudflare deploy
Configure deployment command in your CI/CD system:
npm run deploy
Examples:
.github/workflows/deploy.yml.gitlab-ci.ymlnpm run deployEnvironment variables: Set secrets in Cloudflare dashboard or CI/CD system
Add custom domain in Cloudflare dashboard:
DNS: Domain must be on Cloudflare (zone required)
Generate types for Cloudflare bindings:
npm run cf-typegen
Creates cloudflare-env.d.ts with types for your bindings:
// cloudflare-env.d.ts (auto-generated)
interface CloudflareEnv {
DB: D1Database;
BUCKET: R2Bucket;
KV: KVNamespace;
AI: Ai;
}
Use in route handlers:
import type { NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
const env = process.env as CloudflareEnv;
// Now env.DB, env.BUCKET, etc. are typed
}
# Next.js dev server (fast iteration)
npm run dev
# Workerd runtime (catches Workers-specific issues)
npm run preview
Always test in preview mode before deploying:
# Build and run in workerd
npm run preview
# Test bindings (D1, R2, KV, AI)
# Test middleware
# Test API routes
# Test SSR/ISR behavior
npm run previewnpm run deploySame process as Vercel migration - the adapter handles Next.js standard features automatically.
cloudflare-worker-base - Base Worker setup with Hono + Vite + Reactcloudflare-d1 - D1 database integrationcloudflare-r2 - R2 object storagecloudflare-kv - KV key-value storagecloudflare-workers-ai - Workers AI integrationcloudflare-vectorize - Vector database for RAG# New project
npm create cloudflare@latest -- my-next-app --framework=next
# Development
npm run dev # Fast iteration (Next.js dev server)
npm run preview # Test in workerd (production-like)
# Deployment
npm run deploy # Build and deploy to Cloudflare
# TypeScript
npm run cf-typegen # Generate binding types
// wrangler.jsonc
{
"compatibility_date": "2025-05-05", // Minimum!
"compatibility_flags": ["nodejs_compat"] // Required!
}
dev → ✅ Always test preview before deployProduction Tested: Official Cloudflare support and active community Token Savings: ~59% vs manual setup Errors Prevented: 10+ documented issues Last Verified: 2025-10-21
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience