skills/cloudflare-pages-cicd/SKILL.md
Cloudflare Pages CI/CD with preview environments, edge functions, and Wrangler automation. Activate on: Cloudflare Pages, Wrangler deploy, preview environment, edge function, Pages project, Cloudflare Workers integration, custom domain on Pages. NOT for: Worker-specific development (use cloudflare-worker-dev), DNS management (use devops-automator), full-stack app frameworks (use vercel-deployment).
npx skillsauth add curiositech/windags-skills cloudflare-pages-cicdInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert in deploying and automating Cloudflare Pages projects with preview environments, edge functions, and Wrangler CLI.
Request processing needs:
├─ Static assets only → Pages (no functions needed)
├─ <10ms CPU + simple API routes → Pages Functions
├─ 10-50ms CPU + stateful operations → Workers
└─ >50ms CPU or heavy processing → Queues + Workers
Deployment model:
├─ Git-based with previews → Pages Git integration
├─ CI/CD with artifact upload → `wrangler pages deploy`
├─ Local development testing → `wrangler pages dev`
└─ Multi-environment promotion → Direct upload with branch targeting
Framework detected:
├─ Next.js → Use @cloudflare/next-on-pages adapter
├─ Astro/SvelteKit/Remix → Native Cloudflare support
├─ Static site generator → Standard build command
└─ Custom build → Specify exact build command + output dir
Environment variables needed:
├─ Public vars → [vars] in wrangler.toml
├─ Secrets → `wrangler pages secret put`
├─ Preview-specific → Environment-based binding IDs
└─ Build-time only → CI/CD environment variables
Data persistence requirements:
├─ Cache/sessions → KV (global, eventual consistency)
├─ Relational data → D1 (SQL, strong consistency per location)
├─ File storage → R2 (S3-compatible object storage)
├─ Real-time state → Durable Objects
└─ External APIs → Service bindings or fetch()
Preview environment isolation:
├─ Development → Separate binding IDs for all resources
├─ Staging → Shared read-only or staging-specific resources
├─ Production → Live binding IDs
└─ Local dev → `--local` flag with local SQLite/memory KV
Symptoms: Builds consistently timeout at 20+ minutes, "Build exceeded time limit" Root cause: Inefficient dependency installation or missing build cache Fix:
node_modules caching in CI/CDnpm ci instead of npm install--no-bundle
Detection: grep "Build exceeded" build-logs.txtSymptoms: Functions work locally but fail in production with "undefined is not a function" Root cause: Missing environment variables or incorrect binding names Fix:
wrangler.toml matches dashboard bindings exactlywrangler pages deployment tail to debug runtime errorsSymptoms: Preview deployments show production data or fail authentication Root cause: Shared binding IDs between environments Fix:
Symptoms: "Memory limit exceeded" errors, slow response times >5s Root cause: Loading large datasets in Functions (128MB limit) Fix:
Memory usage exceeded in Function logsSymptoms: Manual deploys work but Git pushes don't trigger builds Root cause: Webhook disconnected or incorrect build settings Fix:
Scenario: Next.js app needs branch-based previews + production deploys
Step 1: Decision Points Navigation
Step 2: GitHub Actions Workflow
name: Deploy to Cloudflare Pages
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: npm-${{ hashFiles('package-lock.json') }}
- name: Install and build
run: |
npm ci
npx @cloudflare/next-on-pages
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy .vercel/output/static --project-name=my-app --branch=${{ github.ref_name }}
- name: Comment PR with preview URL
if: github.event_name == 'pull_request'
run: |
PREVIEW_URL="https://${{ github.sha }}.my-app.pages.dev"
gh pr comment ${{ github.event.number }} --body "🚀 Preview: $PREVIEW_URL"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Step 3: Expert vs Novice Catches
Step 4: Quality Gate Validation
[ ] wrangler.toml has compatibility_date within 6 months
[ ] All bindings have separate preview/production IDs configured
[ ] Git integration connected and webhook responding to pushes
[ ] Preview deployments generate unique URLs for each branch/commit
[ ] Build command produces output in specified directory
[ ] Pages Functions use TypeScript with proper Env interface
[ ] Custom domain configured with SSL certificate active
[ ] Build time consistently under 3 minutes
[ ] Environment variables properly scoped (secrets vs vars)
[ ] Deployment notifications integrated with team communication
[ ] Function response times <100ms for simple operations
[ ] Static assets served with proper caching headers
Don't use Cloudflare Pages for:
cloudflare-worker-dev for advanced Workers features, WebSockets, or CPU-intensive tasksdevops-automator for Cloudflare DNS API operations and domain configurationvercel-deployment for frameworks requiring Node.js runtime or complex server logicDelegate to:
tools
Building resilient distributed systems with circuit breakers, retries with full-jitter exponential backoff, retry budgets (per-request 3-attempt + per-client 10% ratio per Google SRE), deadline propagation, and the cascading-failure math (4 layers × 3 retries = 64x amplification). Grounded in Resilience4j, Microsoft Cloud Patterns, AWS Architecture Blog (Marc Brooker), and Google SRE Book.
testing
Designing HTTP cache headers that work correctly across browsers, CDNs, and shared proxies — `Cache-Control` directives per RFC 9111, `stale-while-revalidate` and `stale-if-error` per RFC 5861, the Vary header for varying responses, and surrogate keys for tag-based purging. Grounded in IETF RFCs and Cloudflare/Fastly docs.
development
Use when designing or fixing a Content Security Policy on a real site, choosing between nonce-based and hash-based CSP, adding strict-dynamic, debugging "Refused to execute inline script" errors, deploying CSP in report-only mode first, configuring report-to / report-uri, or auditing an existing policy for unsafe-inline / unsafe-eval / wildcards. Triggers: "CSP blocks legitimate inline script", strict-dynamic, nonce-{RANDOM}, sha256-{HASH}, object-src none, base-uri none, frame-ancestors, Trusted Types, X-Content-Security-Policy obsolete, report-only vs enforced. NOT for general HTTP security headers (HSTS, COOP/COEP), Trusted Types deep dive, CORS configuration, or building a WAF.
tools
Choosing and operating an HTTP API versioning strategy that doesn't break clients — Stripe's date-based pinned versions, the Deprecation/Sunset header pair (RFC 9745 + RFC 8594), URI vs header vs media-type approaches, and the version-transformer pattern. Grounded in Stripe's published architecture and IETF RFCs.