Setting Multiple Environment Variables in React
Tags: react, environmentvariables
Published: 2020-11-18 03:46:25

You might have come across instances where you would want to use a certain value in the development environment and
another value in the production environment,
say for instance there is an API endpoint from which you fetch a list of users.
Now definitely you will have a different URL for each of the environments, such that development data is not fetched in production.

To identify which environment we are in, we can make use of a special environment variable: `process.env.NODE_ENV`.
When you are using Create React App,
the react-scripts will set the value of `NODE_ENV` to `development` when `npm start` is executed and
to `production` when you run `npm run build`.

So you can make use of `NODE_ENV` to determine which environment you are in and
set the value of API endpoint accordingly as shown in the below code snippet

```js
let API_ENDPOINT
if (process.env.NODE_ENV === "production") {
  API_ENDPOINT = "https://example.com"
} else {
  API_ENDPOINT = "https://dev.example.com"
}
```

However, the problem with the above approach would be that we will have to put this check wherever we would want to use the environment-specific values and
if we would want to add an environment or change value for a particular environment,
we will have to scan through the whole codebase, which is a cumbersome task.

To solve this problem, React ships with `.env` file support.
That is, we can have a file named `.env` at the root directory of our project and have the values defined there.
Let's see how we can implement it in the next steps.

# Project Setup

First of all, let's create a new react project using the below command:

```bash
npx create-react-app environment-variables
```

Now in the root directory create 3 files `.env`, `.env.development` and `.env.production` with the following content:

```.env
REACT_APP_API_ENDPOINT = https://default.example.com
```

```.env
REACT_APP_API_ENDPOINT = https://dev.example.com
```

```.env
REACT_APP_API_ENDPOINT = https://example.com
```

Update `App.js` with the following code:

```jsx
function App() {
  console.log({ REACT_APP_API_ENDPOINT: process.env.REACT_APP_API_ENDPOINT })
  return <div>Home</div>
}

export default App
```

In the above code, we are logging the value of `process.env.REACT_APP_API_ENDPOINT`,
which means any value stored inside .env files can be accessed via `process.env`.

> Create React App requires all the environment variables to begin with `REACT_APP_`, any other variables will be ignored.
> This is done to avoid developers from accidentally committing any environment variables that may contain app secrets.

Now let's start the application using `npm start` and see what is logged in the browser console:

![Endpoint Log start](https://dev-to-uploads.s3.amazonaws.com/i/sq8f6fh0e4x499mj4qpr.png)

From this, we can understand that whenever `npm start` is run, `NODE_ENV` will be set to development and
environment variables will be fetched from `.env.development`

Now let's build the application using `npm run build` and try running the application using the below command:

```bash
serve -s build
```

> If you don't have `serve` installed globally, please do so by running `npm i -g serve`

If you open [https://localhost:5000](https://localhost:5000), you will see that endpoint is fetched from `.env.production` and logged.

![Endpoint Log build](https://dev-to-uploads.s3.amazonaws.com/i/r8lysd5odya4hj0m5jtq.png)

[CRA Documentation](https://create-react-app.dev/docs/adding-custom-environment-variables) says that you cannot override `NODE_ENV` manually.
So if you want to have 2 more environments, say qa and staging then you cannot override `NODE_ENV` and expect it to work.

# Having multiple environments

To support multiple environments, we need to install an additional library and modify the build scripts slightly.
Let's install [env-cmd](https://www.npmjs.com/package/env-cmd), as a development dependency using the following command.

```bash
npm i -D env-cmd
```

env-cmd helps in specifying which particular `.env` file to consider while building the application.

So now let's add `.env` files for qa and staging environments:
.env.qa:
```.env 
REACT_APP_API_ENDPOINT = https://qa.example.com
```
.env.staging:
```.env
REACT_APP_API_ENDPOINT = https://stage.example.com
```

And add couple of build scripts to `package.json`

```json
{
  // ...
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "build:qa": "env-cmd -f .env.qa npm run-script build",
    "build:staging": "env-cmd -f .env.staging npm run-script build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }

  // ...
}
```

So now if you run `npm run build:qa` or `npm run build:staging`, and serve the application,
you will see the respective endpoint URL being logged.

![Endpoint Log qa](https://dev-to-uploads.s3.amazonaws.com/i/u47u32b6ns70i8p7x6b2.png)

![Endpoint Log staging](https://dev-to-uploads.s3.amazonaws.com/i/i9agsbdtt0f07702hhjr.png)

# Keeping all the configuration in one file

If you don't like having a separate file for each environment, you can store all the configurations in one file!

Create a file named `.env-cmdrc` in the root directory of the project with the following content:

```json
{
  "development": {
    "REACT_APP_API_ENDPOINT": "https://devapi.example.com"
  },
  "qa": {
    "REACT_APP_API_ENDPOINT": "https://qaapi.example.com"
  },
  "staging": {
    "REACT_APP_API_ENDPOINT": "https://stagingapi.example.com"
  },
  "production": {
    "REACT_APP_API_ENDPOINT": "https://prodapi.example.com"
  }
}
```

Now add few scripts to package.json to read the variables from the above file:

```json
{
  //...
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "build:dev": "env-cmd -f .env.development npm run-script build",
    "build:qa": "env-cmd -f .env.qa npm run-script build",
    "build:staging": "env-cmd -f .env.staging npm run-script build",
    "build-dev": "env-cmd -e development npm run-script build",
    "build-qa": "env-cmd -e qa npm run-script build",
    "build-staging": "env-cmd -e staging npm run-script build",
    "build-prod": "env-cmd -e production npm run-script build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
  //...
}
```

Now build the development code using the command `npm run build-dev`, run the built code using `serve -s build`,
and you will see the correct API URL being printed:

![Endpoint Log dev](https://dev-to-uploads.s3.amazonaws.com/i/aclxk5ts8z08ewjih23u.png)

# Source code

You can view the complete [source code here](https://github.com/collegewap/react-environment-variables).