# Env and secrets

An arc has one `.env`. Compose reads it the way it reads a `.env` beside your compose file: for each `${VARIABLE}` in `docker-compose.yml`, and for `env_file: .env`. Every branch of the arc uses the same one.

Its values are write-only. No command prints one, and a deploy's output hides any value it would show. OmniArc stores the file encrypted, and keeps it apart from the arc's data, so no copy of that data carries it. Your local `.env` is never uploaded with your project.

## Set a variable

The shop's database password is `${POSTGRES_PASSWORD:-shop}`: the arc's value if it has one, `shop` if not. To set it:

```sh
omniarc env set POSTGRES_PASSWORD
```

It asks for the value and does not show what you type. It never takes the value on the command line, so it stays out of your shell history. From a script, pipe it in:

```sh
printf %s "$POSTGRES_PASSWORD" | omniarc env set POSTGRES_PASSWORD
```

Names take letters, digits and `_`, and do not start with a digit. A value with a quote or a line break in it needs `omniarc env push`, below.

Every `omniarc env` command acts on the arc named in `./arc.yaml`, so run them in your project directory, or name the arc with `--arc shop`.

## Set it before the first deploy

Some images read a variable only once. Postgres sets its password from `POSTGRES_PASSWORD` when it creates its database, the first time it starts, and never again. If you deployed the shop from [Get started](https://docs.omniarc.eu/guides/get-started.md), its database already has the password `shop`: set a new one now and, at the next deploy, `web` would connect with it to a database that still has the old one.

So set such secrets before the first deploy. The arc has to exist for that, so create it first:

```sh
omniarc arc create shop
omniarc env set POSTGRES_PASSWORD
omniarc deploy
```

To change one afterwards, change it inside the service too: for Postgres, with `ALTER USER`.

## A change applies at the next deploy

Setting a variable changes no running service. Each branch picks it up at its next deploy. To apply it to production without changing the code, redeploy what it runs:

```sh
omniarc deploy --revision current
```

`omniarc env list` shows which branches are behind, and the command for each.

## Upload a whole file

```sh
omniarc env push
```

Replaces the arc's `.env` with your local `.env`, byte for byte (`--file` names another file). It is refused, and nothing is sent, if the arc does not exist; `--create` creates it. Up to 256 KiB.

A project that keeps its values in several files sends them as one:

```sh
omniarc env push --file .env --file apps/api/.env
```

The files are merged in order: a later file's value for a name replaces an earlier one's. Only the names are printed.

## See and remove

```sh
omniarc env list
omniarc env unset POSTGRES_PASSWORD
```

`list` prints the names, never the values, and the branches whose last deploy predates the current `.env`.

## A variable nobody set

A deploy stops on a `${VARIABLE}` that has no default in compose and is not in the arc's `.env`, with [`unset-variable`](https://docs.omniarc.eu/errors/unset-variable.md). Set it, or give it a default with `${VARIABLE:-value}`.

## Compose secrets and env files

An `env_file` named like a `.env` file (`env_file: ./apps/api/.env`, `config/app.env`) reads the arc's one `.env`, exactly as `env_file: .env` does: on the node each such path is a link to it. Send the values those files hold with `omniarc env push` (several files merge into one, above).

Compose `secrets:` read from a file in your project, and any other `env_file` (`vars.txt`, a path outside the project), are refused. Put the values in the arc's `.env` and read them with `${VARIABLE}` or `env_file: .env`. See [Compose support](https://docs.omniarc.eu/reference/compose-support.md).

Templates such as `.env.example` stay on your machine, and `omniarc check` says nothing about them.

**Example: shop/docker-compose.yml**

```yaml
# A small shop: Postgres holds the products, customers and orders, and
# PostgREST serves them as a JSON API on port 3000.
services:
  web:
    image: postgrest/postgrest:v12.2.12
    environment:
      PGRST_DB_URI: postgres://shop:${POSTGRES_PASSWORD:-shop}@db:5432/shop
      PGRST_DB_SCHEMAS: public
      PGRST_DB_ANON_ROLE: web_anon
      PGRST_SERVER_PORT: 3000
    ports: ["3000:3000"]
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:17
    environment:
      POSTGRES_USER: shop
      POSTGRES_DB: shop
      # Set a real one with `omniarc env set POSTGRES_PASSWORD`, which asks for it.
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-shop}
    volumes:
      - db-data:/var/lib/postgresql/data
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U shop -d shop"]
      interval: 5s
      timeout: 5s
      retries: 10

volumes:
  db-data:
```
