What every dev should know about using Environment Variables

Development11 minutes read

Kadi Kraman

Kadi Kraman

Engineering

Learn how environment variables work, their main usages, common pitfalls, and the best approaches for using environment variables in Expo React Native apps.

What every dev should know about using Environment Variables

Note: This post was originally published in 2024 and has been updated to reflect the current version of Expo.

What are environment variables and how to configure them

An environment variable is a value that is set from outside the program. The purpose of environment variables is to be able to change your program functionality without having to rebuild and/or redeploy the program.

We will look at how environment variables work, their main usages, common pitfalls, and the best approaches for using environment variables in Expo React Native apps.

How do environment variables work?

Using Node.js as an example, you could set an environment variable inline before executing your program:

Code
API_URL=https://api.app.com node code.js

Here, we’re setting API_URL to https://api.app.com and then executing the code in code.js with node. During application initialization, the API_URL variable is loaded into process.env, so that anywhere within code.js, you can access it via process.env.API_URL and it will evaluate to https://api.app.com.

Now say that you had two API environments: development and production. The code in code.js needs to be the same for both, the only difference is that the development version should send requests to http://localhost:3000 while the production version should use https://api.app.com.

Without environment variables, you’d need to hardcode the api url in your codebase and have two separate versions of the file for development and production.

With environment variables however, you can use the exact same code.js file to support both environments by setting the API_URL environment variable to the correct value before executing the program, using

Code
API_URL=http://localhost:3000 node code.js

for development and

Code
API_URL=https://api.app.com node code.js

for production.

Environment variables and security

Is it safe to add secrets to environment variables? Let us first establish what a “secret” is: a secret, in this context, is anything that you wouldn’t be comfortable with anyone else having access to.

For example, your OpenAI apiKey would be a secret, because it is a service where you had to create an account and you pay per request. So any malicious actors using your apiKey would use up your usage limits. Any credentials, private keys or passwords such as ‘database connection strings’ are also secrets.

So is it safe to add secrets to environment variables?

It’s only safe when it is not possible for the user to access the source code where the environment variable is used.

  • websites: not safe, because you can inspect the page source in the browser
  • mobile and desktop apps: not safe, because you can inspect the app source
  • web APIs: safe because the program is run on a server and the source code is hidden

In summary: never store secrets in environment variables that are used in client side code because any code you add to a website or a mobile app (even if it’s added using an environment variable) can be accessed in plain text.

Common uses of environment variables

Environment variables can be used for many scenarios when there is a need for changing specific application runtime behavior. Here are the three most common use cases you’re likely to run into:

  1. Feature toggles: For example, if you’re building an Expo app, and you add EXPO_DEBUG=true in front of any Expo command such as EXPO_DEBUG=true npx expo start, you’ll see additional logging from the process.
  2. Setting environment-specific values: It is common for modern software projects to have at least a development and a production environment, which should connect to the development vs production APIs, payment providers and services respectively. Using environments variables will allow developers to use the same app or website code with only the relevant values replaced.
  3. Storing secrets: As said above - never store secrets in client side code - but for server side code, using environment variables for secrets is paramount. It will allow developers to securely store their code in source control and store the secrets (such as database connection strings, API keys) separately in environment variables that are only pulled out when the server side code is being deployed.

.env files

Storing environment variables in .env files is a widely adopted, though not a standardised approach. With this approach, you will create a file called .env at the root directory of your project and enter all your environment variables as key value pairs:

Code
API_URL=https://api.app.com
ANALYTICS_KEY=key
STAGE=production
LANGUAGE=en

The way you then load and access these variables can vary hugely based on the language and library you use.

Environment variables with Expo

In your Expo apps and Websites, all environment variables that are used in code will have to be prefixed with EXPO_PUBLIC_, so e.g. your API_URL would become EXPO_PUBLIC_API_URL. We designed it this way to make it absolutely clear that anything stored in these environment variables should not be a secret, as it will be used in the frontend code.

These environment variables are inlined during build time. This means that when the JavaScript bundle is being generated, the bundler replaces all instances of EXPO_PUBLIC_API_URL with the actual value in the resulting bundle which is then converted to Hermes bytecode.

There are three ways to set environment variables in Expo projects:

  1. EAS Environment Variables
  2. .env files
  3. eas.json

If you use EAS, you’ll usually end up with a combination of the three to ensure your environment variables are set in all cases.

Using EAS environment variables

EAS (Expo Application Services) is the popular set of integrated cloud services for Expo and React Native apps. Developers use EAS to build, update, and submit their applications.

EAS has first class support for environment variables which you can manage via the Expo website or the CLI. Each project has three environments that mirror the three main build profiles:

  • development: for development client build
  • preview: for other configurations
  • production: for app store build

and are three levels of visibility:

  • plain text: visible on the website, in EAS CLI, and in logs.
  • sensitive: obfuscated in build and workflow jobs logs. You can use a toggle to make them visible on the website. They're also readable in EAS CLI.
  • secret: not readable outside of the EAS servers, including on the website and in EAS CLI. They are obfuscated in build and workflow jobs logs.

A project's environment variables on EAS

Each build profile may be assigned an environment in eas.json:

eas.json
{
"build": {
"production": {
"environment": "production"
...
},
"preview": {
"environment": "preview"
...
},
"development": {
"environment": "development"
...
},
"my-profile": {
"environment": "production"
...
}
}
}

Now whenever you eas build on EAS servers, the environment variables for the configured environment will be used.

Using EAS environment variables for local development

For local development, the EAS environment variables can be pulled down into a local env.local via the EAS CLI:

Terminal
eas env:pull --environment development

Only plain text and sensitive environment variables may be pulled down like this, as secrets can never leave the EAS servers.

Using EAS environment variables for EAS Update

The eas update command supports the --environment flag. For example the following command will create an update using the production environment variables:

Terminal
eas update --environment production

If an --environment flag is not provided, environment variables from any local env files will be used. Note also that the only plain text and sensitive environment variables can be embedded in the update.

Setting environment variables in eas.json

For build profile-specific environment variables, it is also possible to define them in eas.json directly:

Code
{
"build": {
"development": {
"env": {
"APP_VARIANT": "development"
},
...
},
"preview": {
"env": {
"APP_VARIANT": "preview"
},
...
},
"production": {
"env": {
"APP_VARIANT": "production"
},
...
},
"my-profile": {
"env": {
"APP_VARIANT": "development"
},
...
}
},
}

This may be handy for environment variables used in app.config.js, for example your app variant.

Variables set in the eas.json can not be used in eas update or eas deploy.

Environment variables in EAS Hosting

EAS Hosting is a service for deploying your Expo Router web project and API routes. With the ability to deploy API routes - which are fully server side - we are now able to include sensitive environment variables in the server side code.

For deploying a web project with environment variables, note that the environment variables for the client- and server-side code are included at different steps:

  • Running npx expo export --platform web will inline the EXPO_PUBLIC_ variables in the frontend code. The --environment flag is not supported in the export command, so you'll need to pull down the variables you need before building with eas env:pull
  • eas deploy --environment production will include all plain text and sensitive variables for the given environment (in this case, production) in the API routes. If there are any local env files, EAS environment variables loaded with the --environment flag will take precedence over ones defined in .env and .env.local files.

Since secret environment variables are designed to never leave the EAS servers, they cannot be used via the --environment flag which is why it is not currently possible to add secrets to API routes even though it would be safe to do so. Set any values used in API routes as Sensitive.

Environment variables resolution order

When environment variables are set in multiple places, they are resolved in the following order:

eas.json -> .env files -> EAS environment variables

So if the same value was defined in all three, the EAS environment variables one would get applied.

The following caveats exist:

  • eas build will ignore any .env files that are in .gitignore
  • Environment variables that are set in eas.json cannot be used by eas update
  • "Secret" visibility EAS environment variables can only be used during eas build on the EAS servers. They cannot be pulled down locally or included in commands via the --environment flag

Summary

  • Environment variables can be used to change your program functionality - change the API endpoint, enable additional logging, reveal hidden features - from outside the program.
  • Any environment variables in frontend code - websites, mobile apps - are available in plain text so you should never store anything secret in them (such as API keys).
  • EAS environment variables provide a comprehensive environment management solution for Expo React Native projects
  • Environment variables may also be set in .env files and in eas.json
  • With EAS Hosting, client and server side environment variables are embedded at different steps and server side code may include sensitive values like API keys and DB connection strings
environment variables

Dive in, and create your first Expo project

Learn more