Skill 13 · Workers Best Practices
Subchapter 13.1
references/configuration.mdMarkdown6 KBView on GitHub
Use the project’s Wrangler configuration and installed node_modules/wrangler/config-schema.json to check fields and binding declarations. Consult current product docs when a field or compatibility requirement needs verification. Doc paths below are relative to .
https://developers.cloudflare.comSet compatibility_date to today on new projects. Encourage periodic updates on existing projects to adopt new runtime behavior and fixes. Review the intervening compatibility changes and run relevant tests when advancing the date.
Check: compatibility_date exists and supports the affected feature with the configured flags. Recommend updates as maintenance; flag a compatibility defect when the configured date or flags do not support the required behavior.
// wrangler.jsonc
{
"compatibility_date": "$today", // Replace with today's date (YYYY-MM-DD)
"compatibility_flags": ["nodejs_compat"]
}Retrieve: current compatibility dates at /workers/configuration/compatibility-dates/.
The nodejs_compat flag enables Node.js built-in modules (node:crypto, node:buffer, node:stream). Many libraries require it. Missing this flag causes cryptic import errors at runtime.
Check: compatibility_flags includes "nodejs_compat".
{
"compatibility_flags": ["nodejs_compat"]
}Never hand-write the Env interface. Run wrangler types to generate it from the wrangler config. Re-run after adding or renaming any binding.
Check: no manually defined Env or interface Env that duplicates wrangler config bindings. Look for satisfies ExportedHandler<Env> pattern on the default export.
// Generated by wrangler types — always matches actual config
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const value = await env.MY_KV.get("key");
return new Response(value);
},
} satisfies ExportedHandler<Env>;Anti-pattern:
// Hand-written Env that drifts from actual bindings
interface Env {
MY_KV: KVNamespace; // What if the binding name changed?
}Secrets must never appear in wrangler config or source code. Use wrangler secret put and access via env at runtime. Non-secret config goes in vars.
Check: no string literals that look like API keys, tokens, or credentials. Verify .env is in .gitignore for local dev.
{
"vars": {
"API_BASE_URL": "https://api.example.com" // Non-secret: OK in config
}
// Secrets set via: wrangler secret put API_KEY
}Anti-pattern:
{
"vars": {
"API_KEY": "sk-live-abc123..." // Secret in version control
}
}Prefer wrangler.jsonc over wrangler.toml. Newer features are JSON-only. JSONC supports comments for documenting config decisions.
Check: project uses wrangler.jsonc (or wrangler.json). Flag wrangler.toml in new projects.
For executable Worker examples, verify name, compatibility_date, and main against the target Wrangler schema.
env.X reference in code has a corresponding binding declaration in configclass_name matches the exported class nameAn unused binding alone is not a finding; establish a concrete configuration or runtime consequence before recommending a change.
For a new Durable Object class, verify its migration entry and exported class name against the target Wrangler schema.
Enable Workers Logs and Traces in Wrangler config before deploying to production. Set observability.enabled and observability.traces.enabled to true; the top-level setting alone does not enable traces. Use head_sampling_rate to control volume and cost. Use structured JSON logging — console.log(JSON.stringify({...})) — so logs are searchable. Use console.error for errors (appears at error severity in the dashboard).
Check: logs and traces are enabled in the target deployment environment, with neither disabled by an environment override. Check observability.enabled, observability.logs.enabled, and observability.traces.enabled, accounting for their defaults. Logging uses structured JSON, not string concatenation.
{
"observability": {
"enabled": true,
"logs": { "enabled": true, "head_sampling_rate": 1 },
"traces": { "enabled": true, "head_sampling_rate": 0.01 }
}
}// Structured JSON — searchable and filterable
console.log(JSON.stringify({ message: "incoming request", method: request.method, path: url.pathname }));
// Error severity
console.error(JSON.stringify({ message: "request failed", error: e instanceof Error ? e.message : String(e) }));Anti-pattern:
// Unstructured string logs — hard to query
console.log("Got a request to " + url.pathname);Retrieve: Workers Logs (opens in a new tab) and Traces (opens in a new tab) for current config options.