Tuesday, December 19, 2023
A Guide to Expo’s Environmental Variables (Expo v49)
Using environment variables in Expo can be difficult for someone who is new to the SDK. This is because of the SDK’s architecture, which involves Expo GO, custom Development Clients, EAS Build and EAS Update services. It can be hard to coordinate the use of environment variables across all these. And things become more complicated when we want to add variants (stages) to the mix.
In this guide, we show you how to organise your project to handle this challenge effectively.
We have previously written a blog post on how to use environment variables in an Expo app. You can read the article here.
This guide is an updated version that covers the latest features and tools from Expo SDK v49.
Let's jump right in!
Hardcode values to be used in source code
Almost all projects involve configuration options, such as API keys and external URLs, that are utilised by our applications.
It's not advisable to directly "hardcode" these values into our source code.
While this may seem unconventional, it's crucial to remember that there are no real secrets if they are embedded within the application code. Even when stored in environmental variables, they are still bundled into the application package delivered to the client. Therefore, there's little benefit in attempting to keep these values entirely outside our source code.
As a best practice for maintaining clean and organised code, we recommend using a dedicated file where these variables are defined. This file can be named config.ts or env.ts. Subsequently, we consistently reference this file when retrieving these variables. For example:
Use a single Environment variable to set the Stage
Most of the time, we need to have different app variants (stages) that use different external resources (backend APIs, etc). A common basic setup is to have at least two variants of our application: “development” and “production”.
In our practice above, we hardcode the values of the variants. We use an environment variable like EXPO_PUBLIC_APP_VARIANT to switch from one stage to another.
And the rest of our source code consumes the active config:
Now, we just need to set the EXPO_PUBLIC_APP_VARIANT variable in our package.json scripts, and that’s it.
To run the app locally, we need a .env file and run the appropriate script.
To build with EAS Build, we have to add the variant variable in eas.json under the relevant profile so that it applies when the service builds our app.
We should also set up scripts for EAS Update the same way.
This ensures that we use the right stage for each phase of a project’s life cycle (development, build, pushing OTA updates). We maintain control of our variables in one place in our code.
Remember that the variable we use has the EXPO_PUBLIC_ prefix. This is required because our variable is part of our source code. Without this prefix, the variable will be removed during bundling and won’t be in our app.
Dynamic config (app.config.ts)
We can apply the same logic for dynamic configuration. We hard code values that are either part of the app bundle or not sensitive. And then we switch based on EXPO_PUBLIC_APP_VARIANT again. For example:
So, we have achieved to have a single-source of truth for our variables (one for the source code and one for the EAS services).
Handling Real Secrets
Sometimes, we have real secrets that we don’t want to include in the source code of the app. For example, SENTRY_AUTH_TOKEN, which uploads source code files to Sentry service. We have to use environment variables in these cases, even though they add management complexity. So we need to make sure that we keep them updated in the relevant places.
We use a .env file for running the app locally in development mode. The .env file should not be committed to our source control system (git). We add these environment variables to EAS secrets so they are accessible when the eas build command is building a native app on EAS services (and runs the app.config.ts). We ensure that these are also present in our CI/CD environment for running eas update commands and scripts.
Note: We have not mentioned passing variables to the app via the extra props in app.config.ts. Although this method is still supported, it is no longer preferable. We should use EXPO_PUBLIC_ prefixed environmental variables (if we opt out of hard-coding them as suggested above) and directly reference them in our code.
The above are some practices that aim to set up a project with a solid base for most scenarios. Of course, they are not fixed and may change depending on the project’s requirements.
You can find more detailed information in Expo’s relevant documentation: