Skip to content
Back to skills

Cloudflare Pages

ASecurity

Use when deploying a Next.js app to Cloudflare Pages, migrating from Vercel to Cloudflare, troubleshooting edge runtime errors, or evaluating whether a Next.js project is viable on Cloudflare's free or paid plan.

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 13, 2026
ai-agentsbashnextjsnodenodejsapi

Works with

  • api

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned October 13, 2026

npx -y skills add phucbm/skills --skill cloudflare-pages --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cloudflare Pages?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cloudflare Pages
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/phucbm-cloudflare-pages/badge)](https://www.skillsdirectory.com/skills/phucbm-cloudflare-pages)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cloudflare-pages
description: Use when deploying a Next.js app to Cloudflare Pages, migrating from Vercel to Cloudflare, troubleshooting edge runtime errors, or evaluating whether a Next.js project is viable on Cloudflare's free or paid plan.
when_to_use: User mentions Cloudflare Pages, @cloudflare/next-on-pages, @opennextjs/cloudflare, wrangler, worker size limits, or asks about moving a Next.js app off Vercel to Cloudflare.
allowed-tools: Bash, Read, Edit, Write
---

# Migrating Next.js from Vercel to Cloudflare Pages

## Conclusion

Not viable for large Next.js apps on Cloudflare's free plan. The bundled worker size is the hard blocker. Lightweight projects (few dependencies) work fine.

---

## Two Cloudflare Adapters — Pick the Right One

### `@cloudflare/next-on-pages` (older)
- Splits each route into a separate edge function
- **Requires every dynamic route to export `runtime='edge'`**
- Hard incompatibility: Next.js throws if you combine `runtime='edge'` with `generateStaticParams` in the same route
- Any Node.js module (`fs`, `path`, `child_process`) anywhere in a route's import chain breaks the build
- Not recommended for Nextra or content-heavy apps

### `@opennextjs/cloudflare` (recommended)
- Bundles the entire app into a single `handler.mjs` worker
- Does NOT require `runtime='edge'` on all routes
- Supports Node.js APIs via the `nodejs_compat` Cloudflare compatibility flag
- Correct choice for apps with Node.js-dependent server components

---

## Migration Steps (`@opennextjs/cloudflare`)

1. Install: `pnpm add -D @opennextjs/cloudflare wrangler`
2. Create `open-next.config.ts`:
   ```ts
   import { defineCloudflareConfig } from "@opennextjs/cloudflare";
   export default defineCloudflareConfig({});
   ```
3. Create `wrangler.jsonc`:
   ```jsonc
   {
     "$schema": "node_modules/wrangler/config-schema.json",
     "main": ".open-next/worker.js",
     "name": "<your-cloudflare-worker-name>",
     "compatibility_date": "<today>",
     "compatibility_flags": ["nodejs_compat"],
     "assets": {
       "directory": ".open-next/assets",
       "binding": "ASSETS"
     },
     "observability": { "enabled": true }
   }
   ```
   - Worker name must match the name in your Cloudflare dashboard exactly
   - Only add `services` / `WORKER_SELF_REFERENCE` binding if you use ISR (`export const revalidate = X` at page level) — most apps don't need it
4. In Cloudflare Pages dashboard: set build command to `opennextjs-cloudflare build`, output directory to `.open-next/assets`

---

## The Real Blocker: Worker Size

`@opennextjs/cloudflare` collapses everything into one `handler.mjs`. Cloudflare enforces a compressed size limit:

| Plan | Limit |
|---|---|
| Free | 3 MiB |
| Paid | 10 MiB |

**Always measure before deploying:**
```bash
opennextjs-cloudflare build
du -sh .open-next/server-functions/default/handler.mjs
```

Real-world examples:
- Lightweight Nextra docs site (minimal deps): ~4 MB — works on paid, too large for free
- Full-featured Next.js app (Sandpack, GSAP, Radix UI, component registry): ~42 MB — exceeds even the paid plan

**Important:** Shiki language chunks and `.next/server/chunks/` are served as CDN assets and do NOT count toward the worker size limit. The worker size is driven by `node_modules` bundled into the worker context — primarily heavy packages imported by server components or API routes.

---

## If the Worker Is Too Large

Options in order of effort:

1. **Upgrade plan** — only viable if `handler.mjs` is between 3-10 MB
2. **Remove or lazy-load heavy dependencies** — likely candidates: Sandpack, GSAP, icon libraries, OG image generation (`@vercel/og` adds ~3.6 MB via `resvg.wasm`)
3. **Limit Shiki language packs** — configure Nextra/Shiki to only bundle languages actually used
4. **Accept it's not viable** — some apps are simply too large for Cloudflare's worker model

---

## Pitfalls to Avoid

- **`runtime='edge'` on API routes for Cloudflare breaks Vercel** — Vercel's edge bundler may flag Node.js module references that are fine in Node.js runtime. Only add `runtime='edge'` to routes that genuinely need it (stateless, no Node.js APIs). Revert these if moving back to Vercel.
- **`WORKER_SELF_REFERENCE` service binding** — only needed for ISR. The binding name must match your exact worker name or the deploy fails with code 10143.
- **Worker name mismatch** — the `name` in `wrangler.jsonc` must match the Cloudflare dashboard worker name exactly (visible in CI warning if wrong).
- **Cloudflare doesn't auto-update build settings** — when switching adapters on an existing project, manually update the build command and output directory in the dashboard.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.