React deploy stages with Netlify CI/CD

In this article we go over a recipe for defining deployment stages (development, staging, production, etc.) with a React application. We are going to use the Netlify CI/CD service. We are going to see how React can consume environmental variables, and how we can ‘inject’ these at build-time when we are using Netlify service.

The scenario we’ll go through is the following:

  • We have simple React application created using create-react-app command.
  • The app will have to know whether is running in test, development, or production environment.
  • The app will also have the following deploy stages: development, staging, production.

By deploy stages we mean a set of settings for the app to communicate with the external world. For example a per-stage setting is a backend URL to connect to, or a remote database. Or maybe we want to enable some kind of statistics in production only, and not when we run the app in development or tests.

Before continuing we should make clear the following:

DO NOT expose any security-sensitive information in your environment variables (secret API keys, etc.). Environment variables are injected into the code base by create-react-app build scripts, and the source code of web apps is exposed to the user. Even if we use minification, the sensitive information will still be there, ready to be discovered.

NODE_ENV

The create-react-app exposes the context of build/run operation to our React app via the NODE_ENV environment variable. Actually we cannot even override it.

When we run yarn test its value is test. When we run yarn start its value is development. When we build with yarn build it’s value is production.

And we can consume this variable in our React app by reading process.env.NODE_ENV.

For example:

1
<h6>Environment: {process.env.NODE_ENV}</h6>

Thus we can have our app behave differently when it is running on tests, on development and on production.

Other environment variables

We can define other custom environment variables to be consumed in our application. They have to start with the prefix REACT_APP_. This is another security measure to avoid exposing sensitive environment variables.

For example we can have REACT_APP_STAGE, REACT_APP_BACKEND_URL, etc.

Then our React app consumes our variables via process.env.REACT_APP_STAGE, process.env.REACT_APP_BACKEND_URL, etc, same as above.

Netlify: Build per branch

Now that we know how to consume environment variables in our React app we have to configure them in our CI/CD service and have different values for different stage builds.

First step is to configure Netlify to create separate builds for our development and staging branches. Netlify, by default, builds production by monitoring changes in master branch.

Go to Deploy Settings > Build & Deploy > Continuous Deployment > Deploy Context > Edit Settings. There we can define which branches will trigger builds upon changes.

This way Netlify will build each time a change is pushed to each of those branches, and will deploy it in a random unique URL for previewing.

Environment variables per build

Having build per branch in place, we now need to define custom environment variables for each stage.

With Netlify it is recommended to have a netlify.toml file in our root folder to configure our builds per branch. Here’s a sample file that define environment variables per branch/stage:

netlify.toml

1
2
3
4
5
6
7
8
[context.development.environment]
REACT_APP_STAGE = "development"

[context.staging.environment]
REACT_APP_STAGE = "staging"

[context.production.environment]
REACT_APP_STAGE = "production"

There are a lot of configuration options that can go in netlify.toml, for customizing build behavior. You can find them in Netlify Docs.

Happy building!