# Environments

An app can have multiple environments, such as `staging` and `production`. Every Keel command targets one app and environment. Define environments under `environments:` in `keel.yml`; Keel merges each environment's overrides into the app-level configuration.

```yaml
name: acme-api
region: us-east-1                 # app default region

environments:
  staging:
    # no account override → shares the app's account, isolated by name prefix
    services:
      web:
        desired_count: 1

  production:
    region: us-east-1
    account: "111111111111"       # opts into a separate AWS account
    services:
      web:
        desired_count: 3
        cpu: 1024
    database:
      instance: db.r6g.large

default_environment: production
```

If `environments:` is omitted, Keel operates on a single synthetic `default` environment.

## Isolation models

Two isolation models are supported, selectable per environment:

- **Namespace isolation (default):** Environments share an AWS account and use an `<app>-<env>` prefix. Because Keel roles are account-wide, environments in the same account share credentials.
- **Account isolation:** Set `account` and, optionally, `region` to place an environment in another AWS account. Each account-isolated environment stores credentials under `~/.keel/contexts/<app>/<env>/` and requires `keel auth setup` or `keel auth join` in that account.

Resource names, OpenTofu state keys, SSM paths, log groups, and registry entries include the app and environment names.

## How overrides merge

Overrides are merged field by field, so a block only has to name what differs:

| Section | Merge rule |
|---|---|
| `database`, `cache`, `domain` | field by field; unset fields inherit the base |
| `services.<name>` | field by field |
| `services.<name>.environment`, top-level `environment`, `tags` | merged per key; the override wins |
| `secrets` (app or service) | union by name; order follows the base |
| `bindings` | merged by `resource`; an override replaces that one entry |
| `permissions` | appended |
| `resources` | merged per resource name |
| `release`, `waf` | replaced whole |

For example, a `database.instance` override inherits the base block's `engine`, `version`, `storage`, and `multi_az` values. This field-level merge prevents an environment override from resetting unrelated boolean or count fields.

## Selecting an environment

Precedence, highest first:

1. `--env <name>` flag
2. `KEEL_ENV` environment variable
3. The active environment set with `keel env use <name>` (persisted under `~/.keel`)
4. `default_environment` in `keel.yml`

```bash
keel env list                    # list environments and see which one is active
keel env use staging             # persist the active environment for this app
keel env current                 # print the environment the current context targets
keel deploy web --env production # override for a single command
```

## Adding an environment

`keel env add` declares a new environment by editing `keel.yml` in place — comments and key order survive:

```bash
keel env add staging
keel env add production --env-region us-east-1 --account 111111111111
```

When you add the first named environment, Keel also writes the existing implicit `default` environment and keeps it as the default, preserving the current stack name. Run `keel up --env <name>` to provision the new environment. You can also add an environment from the dashboard with `e`.
