Environments
The app has three environments. Each has its own app name, env file and EAS environment:
| Environment | App name | Env file | EAS environment |
|---|---|---|---|
development |
MyApp (Dev) | .env.development |
development |
staging |
MyApp (Staging) | .env.staging |
preview |
production |
MyApp | .env.production |
production |
All three share one bundle id by default, which keeps Firebase, push notifications and signing set up once. To install them side by side, switch to the PACKAGE_NAMES block in env.ts.
Env files
Section titled “Env files”EXPO_PUBLIC_APP_ENV=development # development | staging | productionEXPO_PUBLIC_API_URL=https://dummyjson.com/- Only
.env.exampleis committed. The other three are untracked and gitignored, so a real API key can’t be committed by accident. - You never create them by hand.
yarn installrunsscripts/setup-env.mjs, which creates any missing file from.env.example. Runyarn env:initto do the same on demand. - Existing files are never overwritten. The script only reads them to tell you which keys they’re missing.
.env.developmentstarts with the DummyJSON demo API so the app works on first run. Staging and production start with placeholders.
How switching works
Section titled “How switching works”yarn android:staging → copies .env.staging to .env.local (.env.local wins over everything else) → expo run:android → env.ts validates the values and builds a typed config → app.config.ts reads it for the app name, bundle id and package → your code imports it from @envUsing env values in code
Section titled “Using env values in code”import Env from '@env';
const apiUrl = Env.EXPO_PUBLIC_API_URL;const isProduction = Env.EXPO_PUBLIC_APP_ENV === 'production';Validation
Section titled “Validation”env.ts checks every variable with a Zod schema:
- In development an invalid value logs a warning, so a typo doesn’t stop you working.
- During prebuild and builds (
STRICT_ENV_VALIDATION=1) it fails, so a broken config never reaches native code or a store build.
Adding a variable
Section titled “Adding a variable”- Add it to
.env.example. - Run
yarn env:init. It doesn’t change your existing files, but it lists each one that’s missing the new key. - Fill in the value in each
.env.<env>file. - Add it to the Zod schema in
env.ts. - Read it with
Env.YOUR_VARfrom@env, orprocess.env.EXPO_PUBLIC_YOUR_VAR(Metro needs dot notation, notprocess.env[name]). - Push it to EAS for cloud builds:
yarn env:push:<env>.
Syncing with EAS
Section titled “Syncing with EAS”| Command | Does |
|---|---|
yarn env:pull:<env> |
Downloads the EAS environment’s values into .env.<env> |
yarn env:push:<env> |
Uploads .env.<env> to its EAS environment |
On EAS builds, scripts/eas-pre-install.sh copies the matching .env.<env> to .env.local if it was uploaded (.easignore allows it even though git ignores it). If the file isn’t there, for example in a CI-triggered build, the variables stored in EAS are used. Run eas env:list to check all three environments are filled in.
If an env file gets tracked
Section titled “If an env file gets tracked”git ls-files | grep '^\.env' should print only .env.example. If it shows others, untrack them without losing your values:
git rm --cached .env.development .env.staging .env.production