Skip to content

Cloudflare Pages

Cloudflare Pages is a static hosting platform with serverless edge functions built in. It serves files from Cloudflare’s global CDN (180+ cities) with zero configuration.


  1. Push code to GitHub
  2. Cloudflare runs npm run build -> outputs to dist/
  3. Files in dist/ are deployed to every Cloudflare PoP globally
  4. Files in functions/ are deployed as edge functions alongside

The static files and the functions share the same domain - no CORS, no separate API URL.


public/
_headers <-- security headers applied to every response
_redirects <-- URL redirects processed at the edge
robots.txt <-- copied to dist/ as-is
favicon.svg <-- copied to dist/ as-is
functions/
api/
payment/
create-order.ts <-- becomes POST /api/payment/create-order
verify.ts <-- becomes GET /api/payment/verify
wrangler.toml <-- local dev config (not used by Cloudflare Pages in production)

Any .ts or .js file under functions/ becomes a serverless function. The file path maps to the URL path:

functions/api/payment/create-order.ts -> /api/payment/create-order

Export named functions to handle HTTP methods:

type Env = {
MY_SECRET: string;
};
type PagesContext = {
request: Request;
env: Env;
};
export const onRequestPost = async ({ request, env }: PagesContext) => {
const secret = env.MY_SECRET; // from Cloudflare dashboard
// ...
return new Response(JSON.stringify({ ok: true }), {
headers: { "Content-Type": "application/json" },
});
};
export const onRequestGet = async ({ request, env }: PagesContext) => {
// handle GET
};

Critical: Use context.env.VAR for secrets. import.meta.env.VAR is undefined at runtime in Cloudflare Workers/Functions.


Applies HTTP headers to every response. No server config needed:

/*
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; ...

See the Security headers page for the full CSP template.


https://www.example.com/* https://example.com/:splat 301

This redirects all www.* requests to the apex domain. The rule only fires if www.example.com is also added as a custom domain in the Pages project - otherwise Cloudflare never sees those requests.


Used for local development with wrangler pages dev. Not used by Cloudflare Pages in production.

name = "project-name"
compatibility_date = "2025-06-23"
pages_build_output_dir = "dist"

Setting Value
Build command npm run build
Build output directory dist
Node version 18+ (set via NODE_VERSION env var if needed)

For static sites with Pages Functions:

  • Builds: 500/month free
  • Bandwidth: Unlimited (static files served from CDN)
  • Functions: 100,000 invocations/day free
  • Custom domains: Unlimited

More than enough for any client site.