Create builds for multiple environments in React and AWS Amplify using Env-Cmd
Table of contents
- What is an Environment Variable?
- Why Do You Need to Create Builds for Different Environments?
- Install Dependencies
- Get all Values from AWS Amplify
- Create Env Files for Multiple Environments
- Create Build Commands
- Define Environment Variables in AWS Amplify
- Configuring Build Settings in AWS Amplify
- Conclusion
As a developer, you would at a point in your career need to define environment variables and use them in your React applications, either in single or multiple environments. If your application is hosted on multiple environments on your AWS account, trying to navigate how to ensure your environments are compatible with the variables in your React application might be a hassle. A good solution to this problem is the env-cmd library.
In this article, we will be looking at environment variables and how to use them in our application, why we need to create builds for multiple environments, how to create multiple builds with multiple environments using env-cmd, define environment variables in AWS Amplify, and finally, we will look at how to configure amplify build settings with our application.
Before we proceed, let's have a recap of what an environment variable in a React application means.
What is an Environment Variable?
Environment variables are constant variables that are used for app deployment and are required at build time in React applications.
Using environment variables allows one to hide sensitive information from the general public safely. They allow for flexibility within our applications and also help to avoid changing constant variables which if not done carefully may cause an unnecessary problem in the app.
When developing applications using create-react-app, a NODE_ENV environment variable is provided by default for the production, development, and test environment. This can be used within the app by running the commands "npm run build", "npm start", and "npm run test" for the different environments respectively. Variables can be defined in our React application by creating a .env file in the root folder and then inside this file, your variables are defined like the one we have below;
const REACT_APP_ACCESS_KEY = “12644832xxxxxxxxxxx”
one can use these variables anywhere within our React app like this;
Process.env.REACT_APP_ACCESS_KEY
This pretty much solves our problem, right? But what if we want other environments that do not exist within create-react-app like the staging or QA environment?
How do we solve this?
We will need multiple deploys built across different environments in our application.
Why Do You Need to Create Builds for Different Environments?
Imagine a scenario where you have three different servers to deploy your React application (the development, the QA, and the production environment), and each of these environments has different base URLs and domains. It is not practical to dynamically use these three base URLs in our code, especially if you're deploying to a different environment on AWS using a service like AWS AMPLIFY. How then do we ensure that variables defined in our code match every environment dynamically, every time our app is deployed to a specific environment?
We will need to create three different build commands for deployment. And since React scripts only support development and production environment, we will need to use an NPM package called env-cmd.
Install Dependencies
The first thing we need to do is to install an npm package called ENV-CMD. This library allows you to group environment variables in a .env file and use them in your app by passing them as a script.
Step 1: Install the env-cmd package from NPM
npm i env-cmd
Get all Values from AWS Amplify
Step 2
Let's say you have these three environments in your AWS profile: dev, prod, and QA. If the APIs are built using AWS lambda and API gateway, they will most likely all have different base URLs. So what you have to do is go to your API gateway, copy the values you need for all the environments and paste them into a notepad.
Create Env Files for Multiple Environments
Step 3
Next, create four env files in your project root directory (.env, .env.dev, .env.prod, .env.qa). The .env file will contain only values common to the three environments we have, while the other env files will only contain values unique to them.
For example, we can have a .env file that looks like the one below;
REACT_APP_REGION = us-east-1
//.env.dev file can have the following details;
REACT_APP_PROJECT_BUCKET= "project_dev_-0329xxxxxxx"
REACT_APP_PROJECT_BASE_URL= "https://xxxxxxxdev.execute-api.us-east-1.amazonaws.com"
//.env.prod can also have these values;
REACT_APP_PROJECT_BUCKET= "project_prod_-0329xxxxxxx"
REACT_APP_PROJECT_BASE_URL= https://xxxxxxxprod.execute-api.us-east-1.amazonaws.com
//And lastly, the QA environment can look like this;
REACT_APP_PROJECT_BUCKET= "project_qa_-0329xxxxxxx"
REACT_APP_PROJECT_BASE_URL= https://xxxxxxxqa.execute-api.us-east-1.amazonaws.com
Create Build Commands
After these variables have been defined, the final thing we have to do is to create build commands in our React application for all of these environments. We can create some commands for all the environments (build: dev, build: prod, build: qa) and include them in our package.json file as scripts.
This is what these commands look like;
"build:dev": "env-cmd -f .env.dev react-scripts build",
"build:qa": "env-cmd -f .env.qa react-scripts build",
"build:prod": "env-cmd -f .env.prod react-scripts build",
These commands now have to be added to the script value in package.json. After that has been done, our script value will look like this;
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"build:dev": "env-cmd -f .env.dev react-scripts build",
"build:qa": "env-cmd -f .env.qa react-scripts build",
"build:prod": "env-cmd -f .env.prod react-scripts build",
},
Another thing we might want to do is to start these different environments locally. For example, a bug might exist in the QA environment but not in the dev. So how do you switch between environments, making sure they start correctly on your local server? We can achieve this by adding the below scripts to the script value in our package.json file.
"start:prod": "env-cmd -f .env.prod react-scripts start"
"start:dev": "env-cmd -f .env.dev react-scripts start",
To start the production and dev environments, the commands "npm run start: prod" and "npm run start: dev" can be used respectively.
Finally, it is important to create builds for the different environments available, we need to run these commands in other to achieve that;
npm run build:dev
npm run build:prod
npm run build:qa
Define Environment Variables in AWS Amplify
Since we are working with AWS, it is important to ensure that our environment variables are also defined in AWS Amplify. To do this, we need to go to Aws Amplify and click on the environment variables option. Next, we will click on the 'manage variables' button to add a new variable and value to the environment variables table. "ENVIRONMENT" is added as the new variable, "environment name" is included as the value and lastly, we will select our preferred branch.
Our environment table on AWS now finally looks like this;
If we are in the production environment on AWS, the "value" here will be 'prod'. The same is also applicable to the QA environment.
Configuring Build Settings in AWS Amplify
The next thing we have to do is modify our build settings to dynamically match all the builds we have in our local environment and AWS. To do that, click on “build settings” on the left-hand side. We will immediately see an “amplify.yml” file. This file contains different build commands and settings that amplify uses to run the builds for our frontend application.
In our case, we have to include this command "npm build:$ENVIRONMENT" in our YAML file. This will look exactly like the image we have below;
When an app is deployed using AWS Amplify, it's able to detect the type of framework we are using and also the build settings. Amplify can do this by inspecting the package.json file in our repository.
Remember the builds we added to the script value in our package.json?
Amplify then inspect this file, detects the $ENVIRONMENT, and then runs the npm build in the YAML file with the environment variable it detects. That is why it's important to include the command "npm build:$ENVIRONMENT" in the amplify.yml file. The command will assume the $ENVIRONMENT value based on the account the script runs in, which can either be the prod, dev, or QA account on AWS.
Conclusion
Using environment variables in deploying our applications provides flexibility while working in the different environments in our React application. It saves us the hassle of having to write different codes to make our app compatible with the different environments we have.