env.dev

Cloudflare Workers Environment Variables

Configure Workers bindings, secrets, Wrangler environments, local .dev.vars precedence, and Node process.env behavior.

By env.dev Updated

Cloudflare Workers exposes runtime configuration as bindings on the handler's env argument. Plain vars are visible configuration, secrets are encrypted bindings, and Vite-prefixed values are build-time constants that can land in a browser bundle. Mixing those channels is how staging values get frozen into production code or secrets get committed to Wrangler configuration.

A minimal runtime variable

wrangler.jsonc
{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "name": "env-demo",
  "main": "src/index.ts",
  "compatibility_date": "2026-09-14",
  "vars": { "APP_MODE": "development" }
}
src/index.ts
interface Env { APP_MODE: string }

export default {
  fetch(_request: Request, env: Env): Response {
    return new Response(env.APP_MODE);
  },
} satisfies ExportedHandler<Env>;
Synthetic check
npx wrangler dev
curl http://localhost:8787
Expected response
development

Keep the example non-secret. Add deployed secrets with wrangler secret put NAME and local secrets with an ignored .dev.vars or .env file.

Local file precedence is asymmetric

Wrangler 4 uses .dev.vars in preference to dotenv files. If it exists, Wrangler does not load .env into the Worker. An environment-specific .dev.vars.staging replaces the generic file, so repeat every required key. Dotenv variants merge instead, with the most specific file winning per key.

Environment replacement
# .dev.vars
API_ORIGIN="https://dev.example.invalid"
FEATURE_MODE="safe"

# .dev.vars.staging must repeat FEATURE_MODE if required
API_ORIGIN="https://staging.example.invalid"

npx wrangler dev --env staging

Named environments do not inherit vars or secrets

Wrangler's vars and secrets are non-inheritable. Define each binding in every named environment that uses it. This duplication prevents production from silently inheriting a development endpoint.

json
{
  "vars": { "APP_MODE": "development" },
  "env": {
    "production": { "vars": { "APP_MODE": "production" } }
  }
}

Bindings, process.env, and Vite are different

Prefer typed bindings because env also exposes KV, R2, and services. process.env can be populated when Node compatibility is enabled; nodejs_compat_populate_process_env defaults on for compatibility dates from 2025-04-01. One exception matters: Wrangler and the Cloudflare Vite plugin replace process.env.NODE_ENV at build time. Client-side import.meta.env.VITE_* is also public, build-time data. See the build-time env guide.

Check dotenv syntax with the env validator or create a dotenv starting point with the env config builder.

Limitations and version scope

  • vars are not encrypted. Never store tokens in Wrangler configuration.
  • Runtime bindings cannot change JavaScript already emitted into static assets.
  • Node compatibility does not make every Node.js API fully implemented.

This guide targets Wrangler 4 and Workers behavior documented on September 14, 2026. Pin Wrangler in CI and review compatibility-date changes before relying on new runtime behavior.

Primary references

Was this helpful?

Stay up to date

Get notified about new guides, tools, and cheatsheets.