React Native Environment Variables
An app runs in several settings during its life. Developers test against a practice server, testers check a staging copy, and real users connect to the production server. Each setting needs different addresses, keys, and switches. Environment variables hold those differences outside the code, so one codebase serves every setting without edits.
The Idea in Pictures
Same app code
│
┌────┼─────────────┐
▼ ▼ ▼
Development Staging Production
api.dev.com api.test.com api.example.com
test keys test keys real keys
debug on debug on debug off
Why Not Hard-Code Values?
- Changing a server address would force edits in many files
- A forgotten test address could ship to real users
- Secret keys placed in code end up in version control history
- Different team members need different local settings
Using .env Files in Expo
Expo reads variables from .env files. Names that begin with EXPO_PUBLIC_ become available inside the app code.
# .env
EXPO_PUBLIC_API_URL=https://api.dev.example.com
EXPO_PUBLIC_APP_NAME=Notes Dev
EXPO_PUBLIC_ENABLE_LOGS=true
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
const showLogs = process.env.EXPO_PUBLIC_ENABLE_LOGS === 'true';
console.log('Calling', apiUrl);
Variables arrive as text. Convert them yourself, so the string 'true' must be compared with === 'true'.
Several Files for Several Settings
.env Shared defaults .env.development Local development values .env.production Production values .env.local Personal overrides (never shared)
Expo loads .env first and layers the matching file on top, using the current build mode.
A Critical Safety Rule
Every value that ships inside the app bundle can be extracted by a determined person. The EXPO_PUBLIC_ prefix serves as a reminder. Use it only for values that are safe to expose, such as an API address or a public analytics key.
Safe in the app Never in the app ────────────────────── ───────────────────────────── API base URL Database admin password Public map key (restricted) Payment secret key Feature flags Private signing keys Analytics project ID Server-to-server tokens
Keep real secrets on a server. The app calls the server, and the server uses the secret.
Keep .env Files Out of Version Control
Add private files to .gitignore.
# .gitignore
.env.local
.env*.local
.env.production
Commit a safe template named .env.example that lists variable names with empty values. New team members copy it and fill their own.
# .env.example
EXPO_PUBLIC_API_URL=
EXPO_PUBLIC_APP_NAME=
Central Config File
Read variables in one module. Screens import clean values and the project gains one place for defaults and checks.
// src/config/index.js
const required = (name, value) => {
if (!value) {
throw new Error(`Missing environment variable: ${name}`);
}
return value;
};
export const config = {
apiUrl: required('EXPO_PUBLIC_API_URL', process.env.EXPO_PUBLIC_API_URL),
appName: process.env.EXPO_PUBLIC_APP_NAME ?? 'Notes',
enableLogs: process.env.EXPO_PUBLIC_ENABLE_LOGS === 'true',
};
The check stops the app early with a clear message instead of failing later with a confusing network error.
Per-Build Settings with app.config.js
Static app.json cannot read variables. A dynamic app.config.js file can, so each build gets its own name and identifier.
// app.config.js
const isProd = process.env.APP_ENV === 'production';
export default {
expo: {
name: isProd ? 'Notes' : 'Notes Dev',
slug: 'notes',
ios: { bundleIdentifier: isProd ? 'com.acme.notes' : 'com.acme.notes.dev' },
android: { package: isProd ? 'com.acme.notes' : 'com.acme.notes.dev' },
},
};
Different identifiers let testers install the development and production versions side by side.
Feature Flags
A flag switches a feature on or off per environment. A half-finished screen can ship hidden and appear only in staging.
{config.enableNewCheckout && <NewCheckoutButton />}
Build Service Variables
Cloud build services such as EAS store variables in project settings or in eas.json profiles, so secrets stay off developer laptops and out of the repository.
Common Mistakes
- Editing
.envwithout restarting the development server - Committing real keys to a public repository
- Assuming a value is a boolean instead of text
- Forgetting to set variables in the build service
Summary
Environment variables separate settings from code. Use EXPO_PUBLIC_ variables for values safe to expose, keep private files out of version control, centralize reading in a config module, and use app.config.js for per-build identity. Store real secrets on servers, never inside the app.
