How to dynamically change your React Environment variables without re-building
Tags: react, devops, javascript, webdev
Published: 2021-10-12 08:26:46

**Have you ever needed to deploy a React application to multiple environments?**

If you've ever had to do the above, then this scenario may sound familiar to you: _You already have an existing build file, you wish to change some environment variables, then re-deploy it to a new environment._

Unfortunately, you soon realize that the environment variables have been hard-coded within the build file. This means that you cannot change the environment variables without re-building.

**Are there any other ways to modify environment variables?**

We asked around to see if the other projects had a better way to handle it. It turned out that different teams had their own approach:

- Some teams simply re-built it for each environment
- Some teams fetched the environment variables asynchronously from an external data source
- One team stored all the environment variables in the app, then selected the environment based on the URL
- One team stored a placeholder environment variable, then replaced it before serving the file

**What would an ideal flow look like?**

All of the above had certain tradeoffs that we weren't willing to make. We were looking to build something that fulfilled the following:

1. Does not require a rebuild
2. Minimal code change required
3. Allows synchronous access of environment variables
4. Easy to integrate with your current workflow
5. Simple and straightforward

_____

## react-inject-env: a tool that allows you to modify environment variables after the static file has been built

The short and simple explanation is that it creates an `env.js` file in the `/public` folder. The file is then executed at the start and the variables are loaded into the `window` object.

### Here's how to use it

1. Install react-inject-env

```bash
npm install react-inject-env --save-dev
yarn add react-inject-env --dev
```

<br/>2. Add the following to `index.html`
```html
<script src='/env.js'></script>
```

<br/>3. Create a new file called `env.js` and copy the following code:
    
```js
export const env = { ...process.env, ...window['env'] }
```

<br/>4. Replace all instances of `process.env` with the newly created `env` variable
```jsx
import { env } from './env'

export const App = () => {
return (
  <div style={{backgroundColor: env.REACT_APP_COLOR}}>
    <span>{env.REACT_APP_MAIN_TEXT}</span>
  </div>
  )
}
```

<br/>5. Build your static files using `npm run build` / `react-scripts build` / whatever your build script is.

<br/>6. Set your environment variables using the following command:

```shell
[env variables] npx react-inject-env set
    
# with a black background
REACT_APP_COLOR=black REACT_APP_MAIN_TEXT="Black Background" npx react-inject-env set

# with a blue background
REACT_APP_COLOR=blue REACT_APP_MAIN_TEXT="Blue Background" npx react-inject-env set

# for windows
set REACT_APP_COLOR=navy&& set REACT_APP_MAIN_TEXT=Navy Background&& npx react-inject-env set
```

<br/>7. Open `build/env.js` to verify that your variables are present. 

These variables will then be read by your app at runtime.

![build/env.js screenshot sample](https://i.imgur.com/4Cn4kfH.png)

**And that's it, you're done!**

If you need to modify your environment variables again, you can either (a) _repeat *Step #6*_, or (b) _modify `build/env.js` directly_.

_____

## What about \<insert tool\>?

This utility was built to be as simple as possible, so it should integrate and work well with most other tools.

**.env / dotenv**

`react-inject-env` will automatically detect environment variables in your `.env` file located in your root folder.

_Note: Environment variables passed in through the command line will take precedence over `.env` variables._

**Typescript**

In _Step #2_, create a file named `env.ts` instead of `env.js`

```typescript
declare global {
  interface Window {
    env: any
  }
}

// change with your own variables
type EnvType = {
  REACT_APP_COLOR: string,
  REACT_APP_MAIN_TEXT: string,
  REACT_APP_LINK_URL: string,
  REACT_APP_LOGO_URL: string
}
export const env: EnvType = { ...process.env, ...window.env }
```

**Docker**

react-inject-env can also be neatly integrated with Docker

```dockerfile
FROM node:16.10-slim
COPY . /app
WORKDIR /app

RUN npm install
RUN npm run build

EXPOSE 8080

ENTRYPOINT npx react-inject-env set && npx http-server build
```

```shell
docker build . -t react-inject-env-sample-v2
```

```shell
docker run -p 8080:8080 \                   
-e REACT_APP_COLOR=yellow \
-e REACT_APP_LOGO_URL=./logo512.png \
-e REACT_APP_MAIN_TEXT="docker text" \
-e REACT_APP_LINK_URL=https://docker.link \
react-inject-env-sample-v2
```

_____

## Summary

This package has greatly enhanced our workflow and has cut our build and deployment times by over 10 minutes. In the past, we had to build 4x times - once for each environment - but now we only need to build it 1x. Deployments are blazing fast now!

It was built with simplicity in mind, so regardless of which tool you are using, you should be able to integrate it as part of your workflow!

**Links**

For more detailed information and support and samples, you may check out the following links:

- [Samples](https://github.com/codegowhere/react-inject-env/tree/develop/sample/v2)
- [GitHub](https://github.com/codegowhere/react-inject-env#readme)
- [npm](https://www.npmjs.com/package/react-inject-env)