Skip to content
Back to Deployment

Cloudflare Pages Deployment Guide

Git-connected static and SSR deploys on Cloudflare's global edge network with Workers and Functions.

EdgeBeginner

Why

Cloudflare Pages serves static assets and SSR from 300+ edge locations with no cold starts and free unlimited bandwidth on the free plan. Workers integrate for edge logic (auth, A/B testing, geo-routing) with 0ms cold start, unlike serverless functions on other platforms.

Cloudflare's edge network spans 330+ cities with sub-50ms p95 latency globally. Edge functions reduce TTFB by 60-80% compared to origin servers, and Akamai reports 40% of enterprises now use edge compute in 2024.

When

Choose Cloudflare Pages for static sites, Astro/Next.js SSR, edge-heavy apps (geo-routing, auth at edge), and cost-sensitive projects needing free unlimited bandwidth. Avoid if you need long-running processes or heavy compute (use Fly.io or a VPS).

How

1. Connect repo — dash.cloudflare.com → Pages → Create → connect GitHub/GitLab 2. Set build — framework preset (Astro/Next) auto-detects, or set build command + output dir manually 3. Environment vars — set in dashboard, NODE_VERSION=20 for pinned runtime 4. Preview deploys — every PR gets a <branch>.<project>.pages.dev URL automatically 5. Production — push to main (or configured branch), deploy is atomic with instant rollback 6. Functions — /functions directory, each file becomes an edge endpoint (e.g. /functions/api/geo.ts) 7. Custom domain — add CNAME to <project>.pages.dev, Cloudflare manages TLS automatically 8. Wrangler CLI — npx wrangler pages deploy ./dist for manual deploys or CI outside git integration

Example

// functions/api/geo.ts — edge function (runs on Cloudflare Workers runtime) export const onRequest: PagesFunction = async (context) => { const country = context.request.cf?.country || "unknown"; const city = context.request.cf?.city || "unknown"; return Response.json({ country, city, message: `Served from edge near ${city}, ${country}`, timestamp: Date.now(), }); }; // _routes.json — control which paths run Functions vs static { "version": 1, "include": ["/api/*"], "exclude": ["/api/static/*"] } // wrangler.toml — for advanced config + bindings name = "my-pages-app" compatibility_date = "2024-09-01" pages_build_output_dir = "./dist" [[d1_databases]] binding = "DB" database_name = "my-db" database_id = "abc-123" # Deploy via CLI (e.g. from GitHub Actions) # npx wrangler pages deploy ./dist --project-name=my-app --branch=main

Common Problems

  • ⚠Build fails with 'wrangler not found' — Pages dashboard needs wrangler in devDependencies, not global
  • ⚠Functions timeout at 30s — edge CPU limit, move long tasks to a Durable Object or external service
  • ⚠D1 database not bound — wrangler.toml binding name doesn't match env.DB reference in code
  • ⚠Custom domain shows 'pending' — DNS propagation takes up to 24h, or CNAME points to wrong target

Best Practices

  • ✓Pin @cloudflare/workers-types and wrangler versions — edge runtime API changes between versions
  • ✓Use _routes.json to limit Functions to /api/* — static assets served faster without function invocation
  • ✓Set compatibility_date in wrangler.toml — opt into stable runtime features predictably
  • ✓Use D1/KV/R2 bindings for state — edge functions are stateless, persistence needs a binding

FAQ

How is Cloudflare Pages different from Vercel?

Pages runs on Cloudflare's edge network (300+ cities) with no cold starts, while Vercel runs in a single region by default. Pages is free for unlimited static sites; Vercel charges per bandwidth beyond the free tier.

Can I use server-side rendering on Pages?

Yes, via Pages Functions (Workers) — add a functions/ folder with on-demand routes. They run on the edge with a 50ms CPU limit. For heavy SSR, use a Node.js framework on a different platform.

Why is my build failing with wrangler not found?

Pages uses its own build environment — install wrangler as a devDependency and set the build command to npx wrangler pages deploy. For framework presets (Next.js, Astro), select the preset in the dashboard instead.

How do I set up a custom domain on Pages?

Add the domain in the Pages dashboard, then add a CNAME record pointing to your-pages-project.pages.dev. Cloudflare-managed domains are automatic. DNS propagation takes under 60s on Cloudflare's network.

How do I deploy a monorepo to Pages?

Set the root directory in the Pages dashboard to your app folder. Pages builds only that directory. For Turborepo, use npx turbo run build --filter=<app> as the build command.