Skip to content

How To Correctly Build a Multi-Environment React App

Keep one dedicated build folder per environment

When developing a React application, you might need to deal with different environments. Based on my experience, you should consider at least the following three environments:

  • Development
  • Staging
  • Production

Before deploying your React app to one of the last two environments, you need to build it. This is usually achieved by running a command aimed at creating a deployable build saved in your project’s build folder.

Such a method has a tremendous downside. For example, you cannot launch many build commands in parallel. In fact, they all depend on the same folder. As a consequence, when dealing with several environments, this may be a bottleneck.

Plus, since every environment shares the same build folder, it is not intuitive to figure out what the target environment of your last build was. This can lead to errors as well.

Let’s see how to avoid this by correctly building a multi-environment app in React.

1. Installing the Required Dependencies

First of all, you need to add react-app-rewired and env-cmd to your project’s dependencies. You can install both with the following command:

npm install react-app-rewired env-cmd --save

To be able to specify a custom build path, you have to change your webpack configuration. If you created your app by using create-react-app, you might be forced to eject your project — and this should be avoided if not strictly required.

This is where react-app-rewired comes into play!

Note: If your project already uses react-app-rewired, you can skip the following two steps.

Thanks to it, you can easily tweak the create-react-app webpack config. In order to make everything work, you need to follow the next two steps:

  1. Create a valid config-overrides.js file in your root directory.
  2. Change the existing references from react-scripts to react-app-rewired in the scripts section of your package.json file.

Before:

{ 
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
}

After:

{ 
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
  }
}

You have just rewired your React app and are now ready to define environment-based build paths.

Plus, react-app-rewired allows you to achieve other fantastic goals. For example, defining absolute path aliases to make your imports refactor-friendly.

2. Defining the Environment Files

Now, it is time to define a .env file for each of your environments. Such a file should contain whatever variable whose value depends on the current environment.

Let’s define two .env files where we’ll put the build path depending on the current environment.

The staging .env.staging env file:

REACT_APP_BUILD_PATH=build-staging
# ... (other environment variables)

The production .env.production env file:

REACT_APP_BUILD_PATH=build
# ... (other environment variables)

Note: As stated in the Create React App documentation, every environment variable must start with REACT_APP_.

3. Using the Environment Variable

To read the build path from the environment file and use it as a base path for your builds, define a config-overrides.js file as follows:

const path = require('path');

module.exports = {
    webpack: function(config, env) {
        // your webpack configs
        return config;
    },
    // the paths config used when your React app is builded
    paths: function(paths, env) {
        // reading the build path from the selected .env file
        const buildPath = process.env.REACT_APP_BUILD_PATH
        // defining "build" as a fallback path
        paths.appBuild = path.resolve(__dirname, buildPath ? buildPath : "build"); 
      
        return paths;
    }
}

As you can see, I ensured that the appBuild variable has a valid fallback value. This is extremely important. An empty, null, or undefined string could cause the build process to go terribly wrong, potentially affecting your entire code base.

Then, you should define a build command for each of your .env files. By employing env-cmd, you can pass a custom .env file to your build command by using the -f flag.

Make sure the scripts section of your package.json file contains the following two lines:

"build": "react-app-rewired build",
"build:staging": "env-cmd -f .env.staging npm run build"

By default, the env.production file will be used, so you do not need to specify it in the first command.

Now, you can create an environment-based build with the following commands.

For the staging environment:

npm run build:staging

For the production environment:

npm run build

The builds will be placed in the target path defined in the REACT_APP_BUILD_PATH environment variable. If you followed the example, your staging builds will be created in the build-staging folder, while your production builds in the build folder.

Et voilà! Each of your environments now has a dedicated build folder.

Conclusion

Today, we looked at how to define a build folder for each environment of your React app. This way, you can launch different build commands in parallel and make sure that all of them have their own dedicated target folder. As I have just shown, this can easily be achieved by using react-app-rewire and env-cmd. Plus, such an approach can easily be extended to any number of environments.

Thanks for reading! I hope that you found this article helpful.

nv-author-image

Antonello Zanini

I'm a software engineer, but I prefer to call myself a Technology Bishop. Spreading knowledge through writing is my mission.View Author posts

Want technical content like this in your blog?