skip to content

In an EAS build profile, how do the env and environment fields differ, and which value wins when both define a variable?

level: middleimportance: should knowfreq 30%

answer

  1. one is literal, one is a pointer
  2. env: values committed in eas.json
  3. environment: development, preview, production on EAS
  4. unset environment: guessed from distribution
  5. overlap: profile env wins, with a warning

basics

~20 s

env holds literal variables written in eas.json; environment names an EAS environment whose stored variables are loaded. When both define a name, the profile's env value wins and EAS CLI warns. Without environment, EAS picks production, development or preview from the profile.

solid answer

~50 s

`env` is a literal map in `eas.json`, so it is committed to git: EAS CLI sets it when evaluating `app.config.js` locally and on the build worker. `environment` names an **EAS environment** (`development`, `preview` or `production`) whose variables are stored on EAS servers; EAS CLI loads its plain-text and sensitive variables to resolve the app config, and secret-visibility ones exist only on the worker. When a name is in both, EAS CLI uses the profile's `env` value and prints a warning listing the overlap. If `environment` is unset, EAS guesses: `production` when `distribution` is `store`, otherwise `development` when `developmentClient` is true, otherwise `preview`. Because `distribution` defaults to `store`, a dev-client profile that forgets `"internal"` quietly loads production variables. So I set `environment` explicitly on every profile, keep secrets out of `env`, and remember neither field reaches `eas update`, which takes its own `--environment` flag.

code

json · 18 lines
json
{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "environment": "development",
      "env": { "APP_VARIANT": "development" }
    },
    "preview": {
      "distribution": "internal",
      "environment": "preview",
      "env": { "APP_VARIANT": "preview" }
    },
    "production": {
      "environment": "production"
    }
  }
}

go deeper

for a junior

Recall that env holds values written in eas.json, while environment names a set of variables stored on EAS servers.

for a middle

Explain visibility, where each field applies, the precedence on a clash, and the default resolution from distribution and developmentClient.

for a senior

Show you prevent the dev-client-on-production mistake with explicit environment and distribution, treat the overlap warning as a defect, and keep secrets off git.

for a principal

Decide where configuration authority lives, EAS environments or the repository, so that builds, updates and local runs all read one source of truth.

## Two ways to give a build variables An EAS build needs variables at two moments: when **EAS CLI evaluates the dynamic app config** (`app.config.js` or `app.config.ts`) on the developer's machine or CI runner, and when the **build worker** runs the build steps. A build profile in `eas.json` offers two fields for this, and they work differently. ## env: literal values in eas.json ```json { "build": { "preview": { "env": { "APP_VARIANT": "preview" } } } } ``` - The values are written in `eas.json`, so they are **committed to the repository** and visible to anyone who can read it. - EAS CLI sets them while evaluating the app config locally, and they are set again on the worker. - They are merged through `extends`, key by key. - They are right for **non-secret switches**: a variant name, a feature-flag mode, a public API host. ## environment: a pointer to variables stored on EAS ```json { "build": { "preview": { "environment": "preview" } } } ``` - EAS projects have **environments**, typically `development`, `preview` and `production`, each holding variables created with `eas env:create` or on expo.dev. - Each variable has a **visibility**: plain text, sensitive, or secret. EAS CLI can read plain-text and sensitive variables and uses them when resolving the app config; **secret** variables never leave EAS servers, so they exist only on the build worker. - Nothing about the values is in the repository. ## What happens when environment is omitted EAS CLI resolves an environment anyway, from the profile's other keys: 1. `production` if `distribution` is `"store"`; 2. otherwise `development` if `developmentClient` is `true`; 3. otherwise `preview`. Because `distribution` **defaults to `"store"`**, a profile with `developmentClient: true` but no `distribution` resolves to **production**. That is a classic way for a dev client to talk to production services. Expo's own guidance is to set `environment` explicitly on every build profile. ## When both define the same name EAS CLI loads the environment's variables, then applies the profile's `env` on top. The result is `{ ...environmentVariables, ...profileEnv }`: | Situation | Value used | |---|---| | Name only in the EAS environment | The stored value | | Name only in `env` | The `eas.json` value | | Name in both | The `env` value, and EAS CLI prints a warning naming the overlapping variables | So a stale `env` entry can silently shadow a value someone later rotated on EAS. Treat that warning as a defect. ## A comparison | | `env` | `environment` | |---|---|---| | Where values live | `eas.json`, in git | EAS servers | | Suitable for secrets | No | Yes, with secret visibility | | Available when EAS CLI evaluates app config | Yes | Plain text and sensitive only | | Available on the build worker | Yes | Yes, all visibilities | | Wins on a name clash | Yes | No | | Default when unset | none | inferred from `distribution` and `developmentClient` | ## Beyond the build - Variables from a profile's `env` are **not** used by `eas update`; an update publish selects an EAS environment with its own `--environment` flag, required since SDK 55. Keep build and update environments aligned so a published bundle sees the same values the binary was built with. - Local development reads `.env` files, which should stay out of git; `eas env:pull` can write an environment's readable variables locally. - How `EXPO_PUBLIC_` variables are inlined into the JavaScript bundle is a separate topic; the point here is only which values the build process sees. ## Diagnosing which values a build saw - When a build starts, EAS CLI logs which plain-text and sensitive variables it loaded and from which environment, and, when `environment` was inferred, which one it resolved. - It logs the names that came from the profile's `env`, and warns when a name appears in both places. - On the worker, built-in variables such as `EAS_BUILD=true` and `EAS_BUILD_PROFILE` are set; they are not present when the app config is evaluated locally, so config code must not depend on them for anything that has to match on both sides. ## Practical rules - Set `environment` on every profile; do not rely on inference. - Put only non-secret, per-profile switches in `env`. - Store tokens and keys as secret variables in the EAS environment. - Remove any `env` name that also exists on EAS once the warning appears.

  • Why can an EAS profile with developmentClient true still load production variables?
    If `environment` is unset, EAS checks `distribution` first: `store` resolves to `production`. `distribution` defaults to `store`, so a dev-client profile that omits `"internal"` resolves to production before `developmentClient` is ever considered. Setting `distribution` and `environment` explicitly removes the guess.
  • Why might an app config that reads a secret EAS variable behave differently on a developer's machine than on the build worker?
    Secret-visibility variables never leave EAS servers, so EAS CLI cannot see them while evaluating the app config locally; only the worker has them. Code that reads one must provide a fallback for local evaluation, or the variable should use sensitive visibility if it is needed during config resolution.

saying these in an interview costs you the question

  • The EAS environment's value overrides the profile's env on a clash.
  • env in eas.json is a safe place for API tokens.
  • Without environment, EAS builds load no stored variables at all.
  • Secret EAS variables are available when EAS CLI evaluates app.config locally.
  • eas update reuses the env block of the matching build profile.