# Vars vs secrets on Workers

Two different mechanisms, and mixing them up leaks credentials into places you can see.

## Vars: plaintext, visible

- Set in `wrangler.jsonc` under `vars`, or in the dashboard under Workers and Pages, Settings, Variables and Secrets, Add.
- Visible to anyone with dashboard or config access, and printed in some CLI output. Never put credentials here.
- `vars` is non-inheritable across environments: each `[env.staging]` / `[env.production]` must define its own. The top-level value does not flow down.

## Secrets: encrypted, write-only

- Set with `wrangler secret put MY_SECRET_VALUE` or in the dashboard as a secret type. Values are encrypted and never displayed back.
- For local dev, put them in `.dev.vars` (or `.env`, not both) next to your Wrangler config, in dotenv format. If you define `.dev.vars`, `.env` values are ignored.
- You can declare required secret names with the `secrets.required` config property. When defined, only the listed keys load from `.dev.vars`/`.env`; anything extra is excluded and missing keys produce a warning. Use this so a missing secret fails loudly in dev instead of silently in production.

## The binding angle

Both vars and secrets arrive on `env` in your code. The distinction is storage and visibility, not access. A secret read from `env.MY_SECRET_VALUE` is safe precisely because it was never in your config file or repo.

## Checklist

- `.dev.vars` is gitignored. Always. Check before first commit.
- In CI, secrets come from the CI secret store into `wrangler secret put`, never from a checked-in file.
- After rotating a secret, remember isolate reuse: do not cache clients built from `env` secrets in global scope; construct per request.