Environment variables in Expo
Environment variables are global values that are defined in your system. Without these variables, your operating system wouldn't know what to do when you execute a command like
expo start
. Under the hood, it uses the
PATH
variable to fetch a list of directories to search for the
expo
executable.
Because they are defined globally, these variables are useful to change the behavior of code without changing the code itself. Just like your system behaving "differently" when adding directories to the PATH
variable, you can implement these in your Expo app as well. For example, you can enable or disable certain features when building a testing version of your app, or you can switch to a different API endpoint when building for production.
If you have installed the
expo-constants
module in your managed workflow project, you can access the app manifest's properties. One of these properties is the
.env
property, a property that is
only available when running
expo start
. As the name suggests, it contains some of your system-defined environment variables. For security reasons, only the variables that
starts with REACT_NATIVE_
or EXPO_
are available.
While the .env
property can be useful during development, this property is not available when running expo publish
or expo build
. It should not be used for feature flagging or other app-specific configuration because of this.
In the app manifest, there is also a
.extra
property. Unlike
.env
, this property is included when you publish your project with
expo publish
or
expo build
. The contents of the
.extra
property are taken from your app manifest. By default, this does not add any environment variables, but we can make that happen with the
dynamic app manifest configuration.
Below you can see an example of the dynamic
app.config.js
manifest. It's similar to the
app.json
, but written in JavaScript instead of JSON. The manifest is loaded when starting or publishing your app and has access to the environment variables using
process.env
. With this we can configure the
.extra.enableComments
property without having to change the code itself, like
COOLAPP_COMMENTS=true; expo start
.
export default {
name: 'CoolApp',
version: '1.0.0',
extra: {
enableComments: process.env.COOLAPP_COMMENTS === 'true',
},
};
To use these
.extra
properties in your Expo app, you have to use the
expo-constants
module. Here you can see a simple component rendering the comments component, only when these are enabled.
import Constants from 'expo-constants';
export const Post = props => (
<View>
<Text>...</Text>
{props.enableComments && <Comments />}
</View>
);
Post.defaultProps = {
enableComments: Constants.manifest.extra.enableComments || false,
};
You can also use manifest.extra.enableComments
directly in your if statement, but that makes it a bit harder to test or override.
In the bare workflow, you don't have access to the manifest via the
expo-constants
module. You can still use environment variables using another method, a Babel plugin. This approach replaces all references to
process.env.VARNAME
with the variable contents, and works in both Bare and Managed Workflows.
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: ['transform-inline-environment-variables'],
};
};
After adding the new Babel plugin to your config, you can access the environment variable. Here you can see the same component as above, but without expo-constants
.
export const Post = props => (
<View>
<Text>...</Text>
{props.enableComments && <Comments />}
</View>
);
Post.defaultProps = {
enableComments: process.env.EXPO_COOLAPP_COMMENTS === 'true' || false,
};
Keep in mind that all environment variables are parsed as a string. If you use booleans like true
or false
, you have to check using their string equivalent.
Over time your app grows, and more configuration is added. When this happens, it could get harder to find the correct environment variables to start or build your app. Luckily, there is a concept called "dotenv" that can help when this happens.
A dotenv file is a file with all environment variables, and their value, within your project. You can load these dotenv files in Node with a library called
dotenv
.
Below you can see the dynamic manifest using this
dotenv
library. It imports the
/config
module to automatically load the
.env
and merge it with
process.env
. You can also use it without merging it to
process.env
,
read more about that here.
import 'dotenv/config';
export default {
name: 'CoolApp',
version: '1.0.0',
extra: {
enableComments: process.env.COOLAPP_COMMENTS === 'true',
},
};
The official
transform-inline-environment-variables
plugin does not load the
.env
file. If you want to use these files with Babel, you can use unofficial plugins like
babel-plugin-inline-dotenv
. This plugin will load your
.env
when Babel is building your app.
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: ['inline-dotenv'],
};
};
Never store sensitive secrets in your environment variables. The reason behind this is that your code is run on the client side, and thus including your environment variables in the code itself. You can
read more about this topic here.