Wrangler Configuration
Use this skill when creating or editing wrangler.jsonc, binding Cloudflare resources, generating types, or deciding where configuration belongs.
Rules
- Prefer
wrangler.jsoncfor new examples unless the repository already useswrangler.toml. - Add the
$schemaentry so editors can validate binding configuration. - Bind Cloudflare resources through
env, not ad-hoc REST API calls, when running inside a Worker. - Run
npx wrangler typesafter changing bindings and use generatedEnvtypes in handlers/classes. - Store non-secret structured config in
vars; store credentials withwrangler secret putor a secret store binding. - Keep environment-specific bindings explicit. Do not accidentally point preview/dev at production data.
- Add compatibility flags only when needed, and document why they are needed.
Minimal Worker config
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2026-04-28",
"vars": {
"APP_ENV": "production"
}
}
Binding examples
Use only the bindings required by the current project.
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "cloudflare-app",
"main": "src/index.ts",
"compatibility_date": "2026-04-28",
"assets": {
"directory": "./dist/client",
"binding": "ASSETS"
},
"d1_databases": [
{
"binding": "DB",
"database_name": "app-prod",
"database_id": "REPLACE_WITH_DATABASE_ID"
}
],
"r2_buckets": [
{
"binding": "BUCKET",
"bucket_name": "app-prod-objects"
}
],
"kv_namespaces": [
{
"binding": "CACHE",
"id": "REPLACE_WITH_KV_NAMESPACE_ID"
}
],
"durable_objects": {
"bindings": [
{
"name": "ROOM",
"class_name": "Room"
}
]
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["Room"]
}
],
"queues": {
"producers": [
{
"queue": "jobs",
"binding": "JOBS"
}
],
"consumers": [
{
"queue": "jobs",
"max_batch_size": 10,
"max_batch_timeout": 5
}
]
},
"ai": {
"binding": "AI"
},
"vectorize": [
{
"binding": "VECTORIZE",
"index_name": "documents"
}
],
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "REPLACE_WITH_HYPERDRIVE_ID"
}
],
"compatibility_flags": ["nodejs_compat_v2"]
}
TypeScript Env pattern
Prefer generated types, but when sketching code use explicit interfaces:
export interface Env {
APP_ENV: string;
DB: D1Database;
BUCKET: R2Bucket;
CACHE: KVNamespace;
JOBS: Queue<JobMessage>;
AI: Ai;
VECTORIZE: VectorizeIndex;
ROOM: DurableObjectNamespace<Room>;
HYPERDRIVE: Hyperdrive;
ASSETS: Fetcher;
}
Environment separation
Use named environments for dev/staging/prod only when each binding and variable is intentionally mapped.
{
"name": "app",
"main": "src/index.ts",
"compatibility_date": "2026-04-28",
"env": {
"staging": {
"name": "app-staging",
"vars": { "APP_ENV": "staging" },
"d1_databases": [
{ "binding": "DB", "database_name": "app-staging", "database_id": "STAGING_DB_ID" }
]
},
"production": {
"name": "app-prod",
"vars": { "APP_ENV": "production" },
"d1_databases": [
{ "binding": "DB", "database_name": "app-prod", "database_id": "PROD_DB_ID" }
]
}
}
}
Review checklist
- No production IDs in local-only examples.
-
compatibility_dateis intentional and updated through change control. - Secrets are not committed in
wrangler.jsonc. - Durable Object migrations are append-only and class names match exported classes.
- Queue producers and consumers are bound to the intended queues.
-
nodejs_compat_v2is used only for libraries that require Node compatibility. - Generated types match code references to
env.*.