# Variables and secrets

Your app reads its settings from its environment. Alf has two kinds:

- **Variables**: settings everyone in the organization may see, like `NODE_ENV=production` or `LOG_LEVEL=info`.
- **Secrets**: passwords, API keys and tokens. The app gets them the same way, but once saved nobody can read them in the dashboard again, only replace or remove them. They're not given to builds.

Both are stored encrypted. `PORT` is always set for you.

## Changing them

Open the service's **Variables & secrets** tab, edit, and **Save changes**. Nothing restarts yet: a banner lists what changed ("`STRIPE_KEY` (secret) added · `LOG_LEVEL` changed") with **Deploy changes** and **Discard**. Deploying restarts the containers with the new values (the same image or commit, no rebuild).

So you can change several things and send them out together. Project cards show "changes to deploy" while some are waiting.

From the [command line](/docs/cli#variables-and-running-the-code-here): `alf env set KEY=value` sets and deploys in one go (`--stage` leaves it waiting), `alf env push` sets a `.env` file's lines on the service (passwords and keys as secrets, asking first), `alf env pull` writes the variables to a `.env` file, and `alf run -- <command>` runs your code on your machine with them, its databases connected.

### What other deploys do with waiting changes

Every deployment says what it did with them, in the **Deployments** tab and in what the deploy command and agents get back:

| Deploy | Waiting changes |
| --- | --- |
| **Deploy** button, [pushed code](/docs/deploying-code), an agent's `deploy` | go live with it ("Deployed with 2 staged changes…"), unless you ask to keep them staged (`--keep-staged`) |
| A rollback, a settings change | stay staged ("…still staged and NOT in this deployment") |
| A [candidate](/docs/deployments#candidates-try-a-version-before-it-s-live) | run in the candidate, and go live when it's promoted |

## Pasting a .env file

**Paste a .env file** adds its `KEY=value` lines as variables. Move anything sensitive to secrets afterwards.

## Connecting services

Use the project network's names in your values:

```
REDIS_URL=redis://cache:6379
```

Values are taken as they are (one variable can't refer to another), so a connection string with a password goes in as a whole secret:

```
DATABASE_URL=postgres://app:the-password@db:5432/app   (a secret)
```

## Pointing at another service

A variable can point at another service in the same project instead of repeating its value:

```
DATABASE_URL = postgres://app:${{db.PASSWORD}}@${{db.HOST}}:${{db.PORT}}/app
```

`db` is the other service's address part. The point is that the password lives in one place:
change it on the database, deploy the app, and the app has the new one — nobody has to remember
the second copy.

Alongside whatever that service has set, four things about it are always readable:

| | |
|---|---|
| `HOST` | its name inside the project |
| `PORT` | the port it listens on |
| `URL` | `https://…` if it's public, otherwise `http://host:port` inside the project |
| `NAME` | what it's called |

A service can point at **itself** for those four — that's how it learns its own address
(`${{web.URL}}`) — but not at its own variables.

Two things worth knowing. A reference resolves to what the other service has **stored**, and no
further: if that value is itself a reference, it's left alone. And a reference to a service that
isn't in the project is refused when you save it, rather than turning up in the container as the
text you typed.
