# Workers Configuration and Observability 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.com`. - [Configuration](#configuration): compatibility dates, Node.js compatibility, generated types, secrets, and config format - [Binding consistency](#binding-code-consistency): configuration and code agree - [Observability](#observability): enable logs and traces, configure sampling, and emit structured logs ## Configuration ### Keep compatibility_date current Set `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. ```jsonc // 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/`. ### Enable nodejs_compat 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"`. ```jsonc { "compatibility_flags": ["nodejs_compat"] } ``` ### Generate binding types with wrangler types 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` pattern on the default export. ```ts // Generated by wrangler types — always matches actual config export default { async fetch(request: Request, env: Env): Promise { const value = await env.MY_KV.get("key"); return new Response(value); }, } satisfies ExportedHandler; ``` Anti-pattern: ```ts // Hand-written Env that drifts from actual bindings interface Env { MY_KV: KVNamespace; // What if the binding name changed? } ``` ### Store secrets with wrangler secret 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. ```jsonc { "vars": { "API_BASE_URL": "https://api.example.com" // Non-secret: OK in config } // Secrets set via: wrangler secret put API_KEY } ``` Anti-pattern: ```jsonc { "vars": { "API_KEY": "sk-live-abc123..." // Secret in version control } } ``` ### Use wrangler.jsonc for config 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. --- ### Binding-code consistency For executable Worker examples, verify `name`, `compatibility_date`, and `main` against the target Wrangler schema. 1. Every `env.X` reference in code has a corresponding binding declaration in config 2. Names match exactly (case-sensitive) 3. For Durable Objects: `class_name` matches the exported class name An 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. ## Observability ### Enable Workers Logs and Traces 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. ```jsonc { "observability": { "enabled": true, "logs": { "enabled": true, "head_sampling_rate": 1 }, "traces": { "enabled": true, "head_sampling_rate": 0.01 } } } ``` ```ts // 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: ```ts // Unstructured string logs — hard to query console.log("Got a request to " + url.pathname); ``` **Retrieve**: [Workers Logs](https://developers.cloudflare.com/workers/observability/logs/workers-logs/) and [Traces](https://developers.cloudflare.com/workers/observability/traces/) for current config options.