| name | preferences-cloudflare-wrangler-reference |
| description | Cloudflare wrangler comprehensive reference for Workers, D1, R2, and KV configuration. Load when working with Cloudflare deployment or wrangler.toml. |
Cloudflare wrangler comprehensive reference
Comprehensive configuration reference for Cloudflare Wrangler synthesized from production patterns.
See @~/.claude/skills/preferences-web-application-deployment/SKILL.md for deployment workflows and practical patterns.
Configuration schema
{
"$schema": "node_modules/wrangler/config-schema.json"
}
Enable autocomplete and validation in your IDE by including the schema reference at the top of wrangler.jsonc.
Core configuration
Worker identification
{
"name": "my-cloudflare-worker",
"main": "src/index.ts"
}
Runtime compatibility
{
"compatibility_date": "2025-04-10",
"compatibility_flags": [
"nodejs_compat"
]
}
Important: Update compatibility_date regularly to access new platform features.
Workers.dev subdomain
{
"workers_dev": true
}
Static assets configuration
Serve static assets alongside worker logic (SPAs, SSR apps).
{
"assets": {
"directory": ".output/public",
"binding": "ASSETS",
"not_found_handling": "single-page-application",
"run_worker_first": ["/api/*", "/trpc/*", "/auth/*"]
}
}
Pattern: TanStack Start or similar SSR frameworks serve frontend assets while worker handles API routes.
Build configuration
{
"build": {
"command": "bun run build",
"cwd": ".",
"watch_dir": "src"
}
}
Alternative: Use framework-specific build tools (Vite, etc.) and skip wrangler build command.
Routing configuration
Custom domain routing
{
"routes": [
{
"pattern": "example.com",
"custom_domain": true
},
{
"zone_name": "example.com",
"pattern": "api.example.com/*"
}
]
}
Setup:
- Add domain to Cloudflare DNS
- Configure route pattern in wrangler.jsonc
- Deploy worker - route activates automatically
Observability
{
"observability": {
"enabled": true
}
}
Access observability data: Cloudflare Dashboard > Workers & Pages > [Your Worker] > Metrics
Smart Placement
Automatically places worker near users for optimal latency.
{
"placement": {
"mode": "smart"
}
}
When to use: Geographic user distribution with latency-sensitive workloads.
See: https://developers.cloudflare.com/workers/configuration/smart-placement/
Environment variables
Non-sensitive configuration (vars)
{
"vars": {
"API_URL": "https://api.example.com",
"FEATURE_FLAG_NEW_UI": "true",
"LOG_LEVEL": "info"
}
}
Access in worker:
import { env } from "cloudflare:workers";
const apiUrl = env.API_URL;
const featureEnabled = env.FEATURE_FLAG_NEW_UI === "true";
Sensitive data (secrets)
Secrets not stored in wrangler.jsonc - managed via CLI:
wrangler secret put DATABASE_PASSWORD
wrangler secret list
wrangler secret delete OLD_SECRET
wrangler secret put API_KEY --env production
Access in worker (same as vars):
import { env } from "cloudflare:workers";
const dbPassword = env.DATABASE_PASSWORD;
Cloudflare bindings
Connect to Cloudflare platform resources.
See: https://developers.cloudflare.com/workers/runtime-apis/bindings/
D1 databases (serverless SQL)
{
"d1_databases": [
{
"binding": "DB",
"database_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"database_name": "my-app-db",
"experimental_remote": true
}
]
}
Usage:
import { drizzle } from "drizzle-orm/d1";
const db = drizzle(env.DB);
const users = await db.select().from(usersTable);
Create database:
wrangler d1 create my-app-db
KV namespaces (key-value storage)
{
"kv_namespaces": [
{
"binding": "CACHE",
"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"experimental_remote": true
}
]
}
Usage:
await env.CACHE.put("key", "value", {
expirationTtl: 3600
});
const value = await env.CACHE.get("key");
const data = await env.CACHE.get("key", "json");
await env.CACHE.delete("key");
const list = await env.CACHE.list();
Create namespace:
wrangler kv namespace create CACHE
R2 buckets (object storage)
{
"r2_buckets": [
{
"binding": "BUCKET",
"bucket_name": "my-storage-bucket"
}
]
}
Usage (S3-compatible API):
await env.BUCKET.put("uploads/file.pdf", fileData, {
httpMetadata: {
contentType: "application/pdf"
}
});
const file = await env.BUCKET.get("uploads/file.pdf");
const blob = await file.blob();
await env.BUCKET.delete("uploads/file.pdf");
const list = await env.BUCKET.list({ prefix: "uploads/" });
Create bucket:
wrangler r2 bucket create my-storage-bucket
Service bindings (worker-to-worker communication)
{
"services": [
{
"binding": "BACKEND_SERVICE",
"service": "data-service-production",
"experimental_remote": true
}
]
}
Usage:
const response = await env.BACKEND_SERVICE.fetch(
new Request("https://internal/api/data", {
method: "POST",
body: JSON.stringify({ query: "..." })
})
);
const data = await response.json();
Pattern: Microservices architecture with multiple workers.
apps/
user-application/ # Frontend worker
data-service/ # Backend API worker
auth-service/ # Authentication worker
Browser rendering (headless browser)
{
"browser": {
"binding": "VIRTUAL_BROWSER"
}
}
Usage:
const browser = await env.VIRTUAL_BROWSER.launch();
const page = await browser.newPage();
await page.goto("https://example.com");
const screenshot = await page.screenshot();
const html = await page.content();
await browser.close();
Use cases: Web scraping, PDF generation, automated testing, SEO previews.
Workers AI (AI model inference)
{
"ai": {
"binding": "AI"
}
}
Usage:
const response = await env.AI.run("@cf/meta/llama-2-7b-chat-int8", {
prompt: "What is the capital of France?"
});
const result = await env.AI.run("@cf/microsoft/resnet-50", {
image: imageData
});
const embeddings = await env.AI.run("@cf/baai/bge-base-en-v1.5", {
text: "Hello world"
});
See: https://developers.cloudflare.com/workers-ai/
Queues (async message processing)
{
"queues": {
"consumers": [
{
"queue": "data-processing-queue",
"dead_letter_queue": "data-processing-dlq"
},
{
"queue": "data-processing-dlq",
"retry_delay": 0
}
],
"producers": [
{
"binding": "QUEUE",
"queue": "data-processing-queue"
}
]
}
}
Producer usage:
await env.QUEUE.send({
userId: "123",
action: "process_upload"
});
await env.QUEUE.sendBatch([
{ body: { userId: "123" } },
{ body: { userId: "456" } }
]);
Consumer handler:
export default {
async queue(batch: MessageBatch, env: Env): Promise<void> {
for (const message of batch.messages) {
try {
await processMessage(message.body);
message.ack();
} catch (error) {
message.retry();
}
}
}
}
Create queue:
wrangler queues create data-processing-queue
wrangler queues create data-processing-dlq
Workflows (durable execution)
Long-running, durable processes that survive worker restarts.
{
"workflows": [
{
"binding": "MY_WORKFLOW",
"name": "my-workflow-production",
"class_name": "MyWorkflow"
}
]
}
Workflow definition:
import { WorkflowEntrypoint, WorkflowStep } from "cloudflare:workers";
export class MyWorkflow extends WorkflowEntrypoint {
async run(event: any, step: WorkflowStep) {
const result1 = await step.do("fetch-data", async () => {
return await fetch("https://api.example.com/data");
});
await step.sleep("wait-for-processing", "1 hour");
const result2 = await step.do("process-data", async () => {
return processData(result1);
});
return result2;
}
}
Trigger workflow:
const instance = await env.MY_WORKFLOW.create({
params: { userId: "123" }
});
const status = await instance.status();
Durable Objects (stateful compute)
Strongly consistent, stateful workers with persistent storage.
{
"durable_objects": {
"bindings": [
{
"name": "TRACKER_OBJECT",
"class_name": "EventTracker"
},
{
"name": "SCHEDULER_OBJECT",
"class_name": "TaskScheduler"
}
]
}
}
Durable Object migrations:
Required when adding or modifying Durable Objects.
{
"migrations": [
{
"tag": "v1",
"new_classes": ["TaskScheduler"]
},
{
"tag": "v2",
"new_sqlite_classes": ["EventTracker"]
}
]
}
Durable Object definition:
import { DurableObject } from "cloudflare:workers";
export class EventTracker extends DurableObject {
async fetch(request: Request) {
let count = (await this.ctx.storage.get<number>("count")) || 0;
count++;
await this.ctx.storage.put("count", count);
return new Response(count.toString());
}
async webSocketMessage(ws: WebSocket, message: string) {
}
}
Access from worker:
const id = env.TRACKER_OBJECT.idFromName("global-tracker");
const stub = env.TRACKER_OBJECT.get(id);
const response = await stub.fetch(request);
Use cases: Chat rooms, collaborative editing, counters, rate limiting, session management.
Environment-specific configuration
Override any top-level setting per environment.
{
"name": "my-app",
"vars": {
"API_URL": "https://api-dev.example.com",
"STRIPE_PRODUCT_ID": "price_dev_xxxxx"
},
"d1_databases": [
{
"binding": "DB",
"database_id": "dev-database-id",
"experimental_remote": true
}
],
"env": {
"stage": {
"vars": {
"API_URL": "https://api-stage.example.com",
"STRIPE_PRODUCT_ID": "price_staging_xxxxx"
},
"routes": [
{
"custom_domain": true,
"pattern": "stage.example.com"
}
],
"d1_databases": [
{
"binding": "DB",
"database_id": "stage-database-id",
"experimental_remote": true
}
],
"kv_namespaces": [
{
"binding": "CACHE",
"id": "stage-kv-namespace-id"
}
],
"r2_buckets": [
{
"binding": "BUCKET",
"bucket_name": "my-storage-stage"
}
],
"services": [
{
"binding": "BACKEND_SERVICE",
"service": "data-service-stage",
"experimental_remote": true
}
],
"queues": {
"consumers": [
{
"queue": "data-queue-stage",
"dead_letter_queue": "data-dlq-stage"
}
],
"producers": [
{
"binding": "QUEUE",
"queue": "data-queue-stage"
}
]
}
},
"production": {
"vars": {
"API_URL": "https://api.example.com",
"STRIPE_PRODUCT_ID": "price_production_xxxxx"
},
"routes": [
{
"custom_domain": true,
"pattern": "example.com"
}
],
"d1_databases": [
{
"binding": "DB",
"database_id": "production-database-id"
}
],
"kv_namespaces": [
{
"binding": "CACHE",
"id": "production-kv-namespace-id"
}
],
"r2_buckets": [
{
"binding": "BUCKET",
"bucket_name": "my-storage-production"
}
],
"services": [
{
"binding": "BACKEND_SERVICE",
"service": "data-service-production"
}
],
"queues": {
"consumers": [
{
"queue": "data-queue-production",
"dead_letter_queue": "data-dlq-production"
}
],
"producers": [
{
"binding": "QUEUE",
"queue": "data-queue-production"
}
]
}
}
}
}
Deploy to environment:
wrangler deploy --env stage
wrangler deploy --env production
wrangler dev
Environment-specific secrets:
wrangler secret put DATABASE_PASSWORD --env stage
wrangler secret put DATABASE_PASSWORD --env production
Analytics Engine
Custom analytics with high-cardinality data.
{
"analytics_engine_datasets": [
{
"binding": "ANALYTICS"
}
]
}
Usage:
env.ANALYTICS.writeDataPoint({
blobs: ["user_signup", "web"],
doubles: [1, userId],
indexes: [userId],
});
Query in dashboard: GraphQL API or SQL API for analytics queries.
Version metadata
{
"version_metadata": {
"binding": "CF_VERSION_METADATA"
}
}
Usage:
const metadata = env.CF_VERSION_METADATA;
console.log(`Version ID: ${metadata.id}`);
console.log(`Deployed at: ${metadata.timestamp}`);
Tail consumers
Process logs from other workers in real-time.
{
"tail_consumers": [
{
"service": "log-aggregator"
}
]
}
Log consumer worker:
export default {
async tail(events: TraceItem[], env: Env) {
for (const event of events) {
await env.DB.prepare(
"INSERT INTO logs (message, timestamp) VALUES (?, ?)"
).bind(event.logs[0].message, event.eventTimestamp).run();
}
}
}
Dispatch namespaces (Workers for Platforms)
Deploy user-provided workers dynamically.
{
"dispatch_namespaces": [
{
"binding": "DISPATCHER",
"namespace": "user-workers"
}
]
}
Usage:
await env.DISPATCHER.put("user-123-worker", workerScript);
const worker = env.DISPATCHER.get("user-123-worker");
const response = await worker.fetch(request);
Use case: SaaS platforms allowing customers to deploy custom workers.
mTLS certificates
Mutual TLS for secure service-to-service communication.
{
"mtls_certificates": [
{
"binding": "MTLS_CERT",
"certificate_id": "cert-id"
}
]
}
Usage:
const response = await fetch("https://api.example.com", {
mtls: {
certificate_id: env.MTLS_CERT
}
});
Logpush integration
Stream logs to external destinations (S3, R2, HTTP).
{
"logpush": true
}
Configure logpush destinations in Cloudflare dashboard.
Rate limiting
{
"limits": {
"cpu_ms": 50
}
}
Set CPU time limits per request (default 10ms on free tier, 50ms on paid).
Cron triggers (scheduled events)
{
"triggers": {
"crons": [
"0 0 * * *"
]
}
}
Handler:
export default {
async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext) {
await cleanupExpiredData(env.DB);
}
}
Additional resources