| name | cloudflare-pages |
| description | Deploys applications to Cloudflare Pages including Functions, KV, D1, and R2 bindings. Use when deploying to the edge, building globally distributed applications, or using Cloudflare's ecosystem. |
Cloudflare Pages
Full-stack deployment platform with global edge network.
Quick Start
Install Wrangler CLI:
npm install -g wrangler
Login:
wrangler login
Create project:
npm create cloudflare@latest my-app
Deploy:
wrangler pages deploy dist
Project Setup
Connect Git Repository
- Go to dash.cloudflare.com > Pages
- Create a project > Connect to Git
- Select repository
- Configure build settings
- Deploy
wrangler.toml Configuration
name = "my-app"
compatibility_date = "2024-01-01"
pages_build_output_dir = "dist"
# KV Namespace binding
[[kv_namespaces]]
binding = "MY_KV"
id = "abc123"
# D1 Database binding
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "xyz789"
# R2 Bucket binding
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"
# Environment variables
[vars]
API_URL = "https://api.example.com"
# Secrets (set via CLI)
# wrangler secret put API_KEY
Pages Functions
Basic Function
// functions/api/hello.ts
export const onRequest: PagesFunction = async (context) => {
return new Response(JSON.stringify({ message: 'Hello, World!' }), {
headers: { 'Content-Type': 'application/json' },
});
};
HTTP Methods
// functions/api/users.ts
export const onRequestGet: PagesFunction = async (context) => {
const users = await getUsers();
return Response.json(users);
};
export const onRequestPost: PagesFunction = async (context) => {
const body = await context.request.json();
const user = await createUser(body);
return Response.json(user, { status: 201 });
};
export const onRequestDelete: PagesFunction = async (context) => {
const { id } = context.params;
await deleteUser(id);
return new Response(null, { status: 204 });
};
Dynamic Routes
// functions/api/users/[id].ts
export const onRequestGet: PagesFunction = async (context) => {
const { id } = context.params;
const user = await getUser(id);
if (!user) {
return new Response('Not Found', { status: 404 });
}
return Response.json(user);
};
Middleware
// functions/_middleware.ts
export const onRequest: PagesFunction = async (context) => {
// Auth check
const token = context.request.headers.get('Authorization');
if (!token) {
return new Response('Unauthorized', { status: 401 });
}
// Continue to next handler
return context.next();
};
Typed Context
// functions/api/data.ts
interface Env {
MY_KV: KVNamespace;
DB: D1Database;
MY_BUCKET: R2Bucket;
API_KEY: string;
}
export const onRequest: PagesFunction<Env> = async (context) => {
const { MY_KV, DB, MY_BUCKET, API_KEY } = context.env;
// Use bindings
const value = await MY_KV.get('key');
const result = await DB.prepare('SELECT * FROM users').all();
return Response.json({ value, users: result.results });
};
KV Storage
Basic Operations
// functions/api/kv.ts
interface Env {
MY_KV: KVNamespace;
}
export const onRequest: PagesFunction<Env> = async (context) => {
const { MY_KV } = context.env;
// Write
await MY_KV.put('user:123', JSON.stringify({ name: 'John' }));
// Write with expiration
await MY_KV.put('session:abc', 'token', { expirationTtl: 3600 });
// Read
const user = await MY_KV.get('user:123', 'json');
// Delete
await MY_KV.delete('user:123');
// List keys
const keys = await MY_KV.list({ prefix: 'user:' });
return Response.json({ user, keys: keys.keys });
};
D1 Database
Queries
// functions/api/users.ts
interface Env {
DB: D1Database;
}
export const onRequestGet: PagesFunction<Env> = async (context) => {
const { DB } = context.env;
// Simple query
const { results } = await DB.prepare('SELECT * FROM users').all();
return Response.json(results);
};
export const onRequestPost: PagesFunction<Env> = async (context) => {
const { DB } = context.env;
const { name, email } = await context.request.json();
// Parameterized query
const result = await DB.prepare(
'INSERT INTO users (name, email) VALUES (?, ?)'
)
.bind(name, email)
.run();
return Response.json({ id: result.meta.last_row_id }, { status: 201 });
};
Migrations
-- migrations/0001_create_users.sql
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
# Apply migrations
wrangler d1 migrations apply my-database
R2 Object Storage
// functions/api/files.ts
interface Env {
MY_BUCKET: R2Bucket;
}
export const onRequestGet: PagesFunction<Env> = async (context) => {
const { MY_BUCKET } = context.env;
const { key } = context.params;
const object = await MY_BUCKET.get(key as string);
if (!object) {
return new Response('Not Found', { status: 404 });
}
return new Response(object.body, {
headers: {
'Content-Type': object.httpMetadata?.contentType ?? 'application/octet-stream',
},
});
};
export const onRequestPut: PagesFunction<Env> = async (context) => {
const { MY_BUCKET } = context.env;
const { key } = context.params;
const body = await context.request.arrayBuffer();
await MY_BUCKET.put(key as string, body, {
httpMetadata: {
contentType: context.request.headers.get('Content-Type') ?? undefined,
},
});
return new Response('Uploaded', { status: 201 });
};
export const onRequestDelete: PagesFunction<Env> = async (context) => {
const { MY_BUCKET } = context.env;
const { key } = context.params;
await MY_BUCKET.delete(key as string);
return new Response(null, { status: 204 });
};
Environment Variables
Setting Variables
Via Dashboard: Pages project > Settings > Environment variables
Via wrangler.toml:
[vars]
API_URL = "https://api.example.com"
DEBUG = "false"
[env.production.vars]
API_URL = "https://api.example.com"
[env.preview.vars]
API_URL = "https://staging-api.example.com"
Secrets
# Set secret
wrangler secret put API_KEY
# List secrets
wrangler secret list
# Delete secret
wrangler secret delete API_KEY
Headers & Redirects
_headers File
# Custom headers
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
/api/*
Access-Control-Allow-Origin: *
/*.js
Cache-Control: public, max-age=31536000
_redirects File
# Redirects
/old-page /new-page 301
/blog/* /posts/:splat 301
/api/* /api/:splat 200
# SPA fallback
/* /index.html 200
Durable Objects
// src/counter.ts
export class Counter implements DurableObject {
private value: number = 0;
async fetch(request: Request) {
const url = new URL(request.url);
switch (url.pathname) {
case '/increment':
this.value++;
return new Response(String(this.value));
case '/get':
return new Response(String(this.value));
default:
return new Response('Not Found', { status: 404 });
}
}
}
// functions/api/counter.ts
interface Env {
COUNTER: DurableObjectNamespace;
}
export const onRequest: PagesFunction<Env> = async (context) => {
const id = context.env.COUNTER.idFromName('global');
const stub = context.env.COUNTER.get(id);
return stub.fetch(context.request);
};
Local Development
# Start dev server
wrangler pages dev dist
# With bindings
wrangler pages dev dist --kv MY_KV --d1 DB
# With local persistence
wrangler pages dev dist --persist-to .wrangler/state
Deployment
Production Deploy
# Deploy to production
wrangler pages deploy dist --project-name my-app
Preview Deploy
# Deploy to preview
wrangler pages deploy dist --project-name my-app --branch preview
Rollback
Via Dashboard: Pages > Deployments > [deployment] > Rollback
Analytics
// Enable Web Analytics in dashboard
// Or add snippet to HTML
<script
defer
src="https://static.cloudflareinsights.com/beacon.min.js"
data-cf-beacon='{"token": "YOUR_TOKEN"}'
></script>
Best Practices
- Use bindings - KV, D1, R2 for data storage
- Set proper headers - Security and caching
- Use environment-specific config - Separate prod/preview
- Enable web analytics - Monitor performance
- Use Durable Objects - For stateful edge compute
Common Mistakes
| Mistake | Fix |
|---|---|
| Missing compatibility_date | Add to wrangler.toml |
| Wrong output directory | Match framework output |
| Binding not configured | Add to wrangler.toml |
| Function not found | Use functions/ directory |
| Secrets in code | Use wrangler secret |
Reference Files
- references/bindings.md - KV, D1, R2 bindings
- references/functions.md - Function patterns
- references/workers.md - Workers integration