# Environment variables and .env

Deno does not load `.env` files by default; you opt in explicitly. Reading environment variables is also gated by the `--allow-env` permission.

## Loading .env files

```bash
deno run --env-file main.ts            # discover the first .env from cwd upward
deno run --env-file=.env.local main.ts # explicit file
```

- `--env-file` can be passed multiple times. Within one file the first occurrence of a duplicate wins; across files, the last file specified takes precedence.
- Do not rely on automatic loading: CI and production should consume real environment variables injected by the platform, not files from the repository.
- To load files in code, the standard library `@std/dotenv` works, but it still needs `--allow-read` and `--allow-env`.

## Precise grants

```bash
deno run --allow-env=PORT,API_KEY main.ts
```

```ts title="main.ts"
const port = Number(Deno.env.get("PORT") ?? "8000");
if (!Number.isInteger(port)) throw new Error("PORT must be an integer");

const apiKey = Deno.env.get("API_KEY");
if (!apiKey) throw new Error("API_KEY is required");
```

Validate variables at startup and fail fast; it is far easier to diagnose than an `undefined` surfacing mid-request. List only the variables the program actually reads in `--allow-env`, so third-party dependencies cannot peek at the rest of the environment.

## Common DENO_* runtime variables

| Variable | Purpose |
| --- | --- |
| `DENO_DIR` | Dependency and compile cache directory |
| `DENO_NO_PACKAGE_JSON` | Disable automatic `package.json` resolution |
| `DENO_NO_PROMPT` | Disable permission prompts, equivalent to `--no-prompt` |
| `DENO_NO_UPDATE_CHECK` | Disable new-version checks |
| `DENO_TLS_CA_STORE` | Certificate source, `system` / `mozilla`, defaults to `mozilla` |
| `DENO_CERT` | Load extra CAs from a PEM file, equivalent to `--cert` |
| `DENO_AUTH_TOKENS` | Bearer tokens for private module sources |
| `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` | Proxy settings for module downloads and `fetch` |
| `NO_COLOR` | Disable colored output |

The official documentation is the authoritative full list; do not assume a variable exists from memory in scripts.

## Configuration layering

Following twelve-factor principles, keep every environment-specific value in environment variables:

1. Code may carry only non-sensitive defaults (such as port 8000).
2. Local development uses `.env`, added to `.gitignore`.
3. The repository commits `.env.example` with key names and format notes, never real values.
4. CI and production receive variables injected by the platform and do not read a `.env` from the repo.

<Callout type="warn" title="Secrets stay out of the repo and out of logs">
Treat any committed secret as compromised: rotate it and scrub git history rather than just deleting the latest commit. Redact at the output layer — never print `Deno.env.toObject()`, and never concatenate tokens into error messages.
</Callout>

## Connecting to Deno Deploy

On Deno Deploy, environment variables are maintained in the console app's **Environment Variables** section, or managed with the `deno deploy env` subcommands (Classic's `deployctl` was retired with the platform — do not use it anymore):

```bash
deno deploy env add API_KEY "sk-..." --secret --org <org> --app <app>
deno deploy env load .env.production --org <org> --app <app>
```

`env add --secret` keeps the value hidden in the dashboard and in list output; `env load` bulk-imports a `.env` file. Code still only calls `Deno.env.get()`. When the local `.env` and the platform use the same key names, the code stays unaware of the deployment shape. See [Deno Deploy](/en/docs/deploy/deno-deploy).

Official reference: [Environment variables](https://docs.deno.com/runtime/reference/env_variables/).
