Cloudflare Pages CI/CD
Expert in deploying and automating Cloudflare Pages projects with preview environments, edge functions, and Wrangler CLI.
Decision Points
Compute Platform Selection
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
Build Configuration Strategy
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
Binding Architecture
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
Failure Modes
Build Timeout Death Spiral
Symptoms: Builds consistently timeout at 20+ minutes, "Build exceeded time limit" Root cause: Inefficient dependency installation or missing build cache Fix:
- Add
node_modulescaching in CI/CD - Use
npm ciinstead ofnpm install - Enable Wrangler's incremental uploads with
--no-bundleDetection:grep "Build exceeded" build-logs.txt
Environment Variable Mismatch
Symptoms: Functions work locally but fail in production with "undefined is not a function" Root cause: Missing environment variables or incorrect binding names Fix:
- Verify
wrangler.tomlmatches dashboard bindings exactly - Use
wrangler pages deployment tailto debug runtime errors - Check binding names match interface definition Detection: Runtime errors mentioning "Cannot read property" on env bindings
Preview Environment Poisoning
Symptoms: Preview deployments show production data or fail authentication Root cause: Shared binding IDs between environments Fix:
- Create separate D1/KV/R2 instances for preview
- Use environment-specific binding IDs in wrangler.toml
- Implement environment detection in Functions code Detection: Preview URLs returning production data or 401 errors
Function Memory Exhaustion
Symptoms: "Memory limit exceeded" errors, slow response times >5s Root cause: Loading large datasets in Functions (128MB limit) Fix:
- Move data processing to Workers or external service
- Implement pagination for large queries
- Use streaming responses for big payloads
Detection:
Memory usage exceededin Function logs
Git Integration Drift
Symptoms: Manual deploys work but Git pushes don't trigger builds Root cause: Webhook disconnected or incorrect build settings Fix:
- Reconnect Git integration in Cloudflare dashboard
- Verify build command and output directory match local setup
- Check branch protection rules aren't blocking deployments Detection: Git commits without corresponding deployment notifications
Worked Examples
GitHub Actions CI/CD Pipeline with Preview
Scenario: Next.js app needs branch-based previews + production deploys
Step 1: Decision Points Navigation
- Framework: Next.js → Use @cloudflare/next-on-pages
- Deployment: CI/CD artifacts → Direct upload via Actions
- Environment isolation needed → Separate binding IDs
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
- Novice misses: Caching dependencies (slow builds), branch-specific deployments
- Expert catches: Using commit SHA for preview URLs, proper Next.js adapter, cache keys
Step 4: Quality Gate Validation
- ✅ Preview URL posted to PR
- ✅ Main branch deploys to production domain
- ✅ Build completes under 2 minutes with caching
Quality Gates
[ ] 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
NOT-FOR Boundaries
Don't use Cloudflare Pages for:
- Complex Workers logic → Use
cloudflare-worker-devfor advanced Workers features, WebSockets, or CPU-intensive tasks - DNS/domain management → Use
devops-automatorfor Cloudflare DNS API operations and domain configuration - Full-stack frameworks needing SSR → Use
vercel-deploymentfor frameworks requiring Node.js runtime or complex server logic - Database management → Pages handles bindings only; use dedicated database skills for schema design and migrations
- CDN configuration → Pages handles basic caching; use specialized CDN skills for advanced cache rules and edge logic
Delegate to:
- Heavy compute → Workers + Queues
- Real-time features → Durable Objects
- Database operations → D1 management skills
- Advanced networking → Workers for custom protocols