02 — Wrangler Configuration Standard¶
This document defines the canonical wrangler.toml layout for every Adventive Worker. The goal is that any engineer can open a wrangler.toml in any of our repos and find the same fields in the same places, with the same meanings.
The commented reference implementation lives in
worker-stub/wrangler.toml(GitHub). Clone that file; don't hand-write a new one. This document exists to explain the choices baked into the stub.
Required top-level fields¶
Every wrangler.toml must set, at the top of the file:
| Field | Required | Notes |
|---|---|---|
name |
Yes | The dev Worker name in our naming convention. Per-env names are overridden under [env.staging] and [env.production]. |
main |
Yes | Always src/index.ts. The stub enforces this. |
compatibility_date |
Yes | Pin to a concrete date. Update it deliberately, not reflexively. Bumping requires passing the full QA gate. |
compatibility_flags |
Where needed | Document each flag with a comment explaining why it's enabled. |
workers_dev |
Yes | Set to false for anything customer-facing. A *.workers.dev URL bypasses our DNS and WAF. |
account_id |
No (use env var) | Prefer CLOUDFLARE_ACCOUNT_ID in the engineer's shell / CI. Never commit account IDs that aren't already public. |
Environment structure¶
Three environments, in this order in the file: dev (the top-level, unnamed config), then [env.staging], then [env.production]. Keep that order everywhere — it makes diffs readable.
# Top of file = dev defaults
name = "adv-svc-example-dev"
main = "src/index.ts"
compatibility_date = "2026-04-01"
workers_dev = false
[env.staging]
name = "adv-svc-example-stg"
route = { pattern = "example-stg.adventive.com/*", zone_name = "adventive.com" }
[env.production]
name = "adv-svc-example-prd"
route = { pattern = "example.adventive.com/*", zone_name = "adventive.com" }
Deploy commands then look like:
wrangler deploy # deploys dev (by omission)
wrangler deploy --env staging # deploys stg
wrangler deploy --env production # deploys prd
Bindings — where they go¶
Bindings declared at the top level apply to dev only. Bindings needed in staging or production must be declared again under the corresponding [env.*] section with IDs that point to staging or production resources. This is a Wrangler quirk — not inheriting bindings is deliberate isolation, and our stub includes a blank scaffold so this never gets forgotten.
| Binding type | Per-env scaffold | Why isolation matters |
|---|---|---|
[[kv_namespaces]] |
Yes | Dev must not read/write prod KV. |
[[r2_buckets]] |
Yes | Dev must not overwrite prod objects. |
[[d1_databases]] |
Yes | Dev must not schema-migrate prod. |
[[queues.producers]] / [[queues.consumers]] |
Yes | Dev messages must not land in prod queues. |
[[durable_objects.bindings]] |
Yes | DO state is per-env. |
[vars] |
Yes | Non-secret config values. Dev may differ from prod deliberately. |
vars vs. secrets — never confuse them¶
[vars] is plaintext in wrangler.toml and committed to git. Everyone who clones the repo can read it. Use [vars] only for:
- Feature flags with public-safe names (
ENABLE_NEW_HEADER = true) - Non-secret URLs (
UPSTREAM_API_BASE = "https://api.example.com") - Log level (
LOG_LEVEL = "info")
Secrets (API keys, signing secrets, DB credentials, OAuth client secrets) never go in [vars] or wrangler.toml. They go in Cloudflare's encrypted secret store, set via:
See 03 — Secrets & Security Policy for the full policy and the automated scan that enforces it.
Observability — required¶
Every Worker ships with observability enabled. Without this we can't debug production incidents.
[observability]
enabled = true
head_sampling_rate = 1 # 100% during initial rollout; tune down for high-volume Workers
For Workers expected to exceed ~10M requests/month, set head_sampling_rate to a documented value (e.g. 0.1 for 10%) in the per-env block, and note the rationale in a comment.
Tail consumers (for tier-1 services)¶
Tier-1 services (see 05) pipe logs to a separate tail Worker so we have an audit trail even if the primary Worker is rolled back. Pattern:
Triggers — cron Workers¶
Cron Workers declare triggers inside each [env.*] block so dev cron doesn't run against prod resources:
[env.production.triggers]
crons = ["0 */4 * * *"] # every 4 hours — document the schedule in the Worker's README
Size and performance limits — acknowledge them¶
Comment the current Cloudflare limits in the header of every wrangler.toml. They're worth re-reading before every size-affecting PR:
- Worker script: 1 MB compressed (10 MB on Workers Paid + select enterprise plans)
- CPU time: 30 s (paid) / 10 ms (free) — design for the lower bound unless you control the plan
- Subrequests per invocation: 50 (free) / 1000 (paid)
Forbidden patterns¶
- Secrets in
[vars]. Pre-commit hook blocks common patterns; the secret-scan script inscripts/preflight-secrets.shis mandatory in CI. workers_dev = trueon production. Exposes*.workers.devURL that bypasses WAF and DNS.- Hand-written duplicate env blocks instead of using the stub. Leads to drift; use the stub and diff against it during review.
- Inline shell-secret interpolation. Do not write
KEY = "${SOMETHING}"and rely on shell env. Use Wrangler's secret store. - Multiple Workers sharing a single
[[kv_namespaces]]binding ID by convention only. If two Workers genuinely share state, make it explicit by documenting the shared namespace in both repos' READMEs and adding ashared-kv:<namespace>tag.
Review checklist (paste into PRs)¶
Wrangler config review:
- [ ] name matches naming convention, including env suffix
- [ ] main = src/index.ts
- [ ] compatibility_date set and intentional
- [ ] workers_dev = false
- [ ] observability enabled
- [ ] routes set for stg and prd (not dev)
- [ ] bindings duplicated per env, IDs point to correct env resources
- [ ] no secrets in [vars]
- [ ] tail_consumer set if tier-1
- [ ] cron triggers (if any) only under [env.production.triggers] / [env.staging.triggers]
See the live stub: worker-stub/wrangler.toml (GitHub).