Vars, secrets and bindings all arrive on env; they are not the same

Vars are plain text in config, secrets are write-only via wrangler secret put, bindings are live handles to Cloudflare services. Local dev reads .dev.vars.

Getting Started

· Chapter

25

·

3

min read

The answer. Three different things share the env object. Vars ([vars]) are non-secret strings or JSON committed in config; they are visible in the dashboard and in wrangler deploy output. Secrets are set once with wrangler secret put NAME (value from stdin, never a flag) and can never be read back, only overwritten or deleted. Bindings (kv_namespaces, r2_buckets, d1_databases, queues, ai, services) are live handles to Cloudflare resources with methods on them. Locally, wrangler dev reads secrets from a gitignored .dev.vars file and simulates bindings on disk.

The pattern.

printf '%s' "$(op read op://vault/api/key)" | npx wrangler secret put PROVIDER_KEY --env production
npx wrangler secret list --env production        # names only; values are unreadable by design
# .dev.vars — local only, gitignored
PROVIDER_KEY=sk-local-placeholder
// env.PROVIDER_KEY: string   env.CACHE: KVNamespace   env.APP_ENV: string
if (!env.PROVIDER_KEY) throw new Error("PROVIDER_KEY missing");  // fail loudly at the top

Watch out.

  • A secret set in the dashboard and a [vars] key with the same name collide; the deploy tells you, but only if you read the output.
  • Every named environment gets its own secrets. wrangler secret put X without --env targets the top-level Worker, which should not be production.
  • Vars are limited (64 per Worker on Free, 128 on Paid, 5 KB each). Long JSON config belongs in KV or a static asset, not a var.

Related: declare-required-secrets-in-wrangler-config · wrangler-environments-inherit-nothing-that-binds · kill-switch-var-fail-closed-ceilings-fail-open