# Environment variables

Each app's environment lives in the **Env** tab as managed key → value rows. The rows are the source of truth; Pyvolt generates a `.env` file on your server from them and restarts your app so changes take effect.

## Managing rows

- **Add / edit / delete** rows inline. Saving writes the file to `/home/pyvolt/sites/<domain>/.env` and restarts the app service.
- **Secrets** are masked in the UI. Keys that look secret (`SECRET_KEY`, `*_API_KEY`, `*_TOKEN`, `*_PASSWORD`, `*_DSN`) are masked automatically; you can toggle any row.
- **Bulk import** - paste an existing `.env` and preview the merge before saving. **Export** serialises your rows back to `.env` text.

It's all scriptable from the terminal too - for example, upsert a couple of variables:

```cli
pyvolt env myapp.com set SECRET_KEY=xxxx DEBUG=False
```

See the [CLI reference](cli-commands.md#environment-variables) for the full set: `list`, `get`, `set` and `rm`.

## Platform-managed variables

Pyvolt injects a few variables itself - they're shown read-only and can't be overridden by your rows:

| Variable | Value |
|----------|-------|
| `PYVOLT_HOST` | The app's domain - handy for `ALLOWED_HOSTS` / `CSRF_TRUSTED_ORIGINS` |
| `DJANGO_SETTINGS_MODULE` | Your configured settings module (Django apps) |

## Where the variables apply

The same `.env` is loaded by:

- your app process (the start command),
- every [background process](background-processes.md) (workers, schedulers, and any command),
- every [scheduled job](scheduler.md) (cron commands).

One file, one truth - a worker never sees a different environment than the web process.

### Release commands (opt-in)

Release-command steps (migrations, `collectstatic`) run with a minimal
environment by default. If a step needs your variables - the classic case is
`manage.py migrate` reading `DATABASE_URL` - turn on **Expose to release
commands** at the bottom of this tab (or when creating the app, under its env
rows). Apps configured by [pyvolt.toml](pyvolt-toml.md) set it in the file
instead:

```toml
[app]
release_env = true
```

Why opt-in: many release steps never need secrets, and the tighter default
means a leaky build script or verbose migration log can't accidentally print
one. Flip it on when your release steps read config from the environment.

## Databases

Selecting or creating a Postgres database on the app-create form adds a `DATABASE_URL` row automatically (the generated password appears only there - masked). For an existing database the password segment is left for you to fill in.
