What is the deal with Environment Variables in a Front- End Application?

Hey.

How do you deal with environment variables in your Front-end (say React) Application?

But before that, let me give a gist about what it is.

What is Environment Variables?

It is a convention to store all the sensitive information that you deal with in your application (e.g., API Keys, DB URLs, API URLs etc.,) and wrap it in a .env file.

Let's face it. Most of us don't get to do this setup because it turns out you enter into a project whose Project Scaffolding has already been done.

Perhaps, what if you get to be the initial member of a new project and things go over your head while setting up an application from scratch. That's where we configure environment variable setup initially.

Do you ask me is there only a single way to do that. My answer will be an obvious no.

But wait. There is a way which could actually make your way of dealing with environment variables easier.


“Talk is cheap. Show me the code.” ― Linus Torvalds

How to use .env

.env file is not going to be a part of your Git Repo as all the files starting with .env is ignored to be pushed by .gitignore file.


Project Example

Let's look at a very basic React Application Folder Structure using CRA Template.

image.png

After clearing out the boilerplate code, this is how my App.js looks like now:

import "./App.css";

function App() {
  return (
    <div className="App">
      <h1>Hello There. </h1>
    </div>
  );
}

export default App;

I've changed my .gitignore slightly

from this :

.env.local
.env.development.local
.env.test.local
.env.production.local

to this :

.env*

just to make sure all the files that has .env is ignored.

Lets look at the normal use of .env file first.


.env configuration

  • Add a simple .env file into your root directory of the application and write a couple of variables there like below.
REACT_APP_USERNAME  = MARK ZUCKERBERG
REACT_APP_EMAIL_ID = MARK@META.COM
REACT_APP_API_KEY = sdklfjhkqhqoiweipjafklnlaksddlkkaskdj

Making use of variables in the project.

Import these variables into a file or a folder inside src. I've made a properties.js file in my src and it looks like this.

export const properties = {
  userName: process.env.REACT_APP_USERNAME,
  email: process.env.REACT_APP_EMAIL_ID,
  apiKey: process.env.REACT_APP_API_KEY,
};

Use it in your App:

import "./App.css";
import { properties } from "./properties";

function App() {
  const { userName, email, apiKey } = properties;

  return (
    <div className="App">
      <h1>Hello There. </h1>
      <p>{`I am ${userName}`}</p>
      <p>{`My Email ID is : ${email}`}</p>
      <p>{`Take this API key to make a call : ${apiKey}`}</p>
    </div>
  );
}

export default App;

Note : Restart your app after doing this setup as everytime you make changes in .env file you need to restart your server.

Initial Output

image.png


After the development when you actually make the build folder, the variables gets bundled and when you push the code to your Repo, the .env would be ignored, so the variables stays within your local Repository.

But is the issue solved yet?

What else to do?


The actual problem with environment variables

Lets say you are working in a production level Application and you have different sets of data for Development, Acceptance and Production.

And for each of those Environments, you might need different API keys or entirely different APIs as well.

How do you differentiate or prioritize which key to use without any hassle in your code setup.

The steps to do this :

  1. Delete the initially created .env file from the root directory.
  2. Download the env-cmd package using npm install env-cmd command.
  3. Create a file .env-cmdrc.json file in your root directory.

.env-cmdrc.json looks like this:

{
  "dev": {
    "REACT_APP_USERNAME": "MARK ZUCKERBERG from dev",
    "REACT_APP_EMAIL_ID": "MARK@META-DEV.COM",
    "REACT_APP_API_KEY": "sdklfjhkqhqoiweipjafklnlaksddlkkaskdj-dev-api"
  },
  "acceptance": {
    "REACT_APP_USERNAME": "MARK ZUCKERBERG from Acceptance",
    "REACT_APP_EMAIL_ID": "MARK@META-ACCEPTANCE.COM",
    "REACT_APP_API_KEY": "sdklfjhkqhqoiweipjafklnlaksddlkkaskdj-acceptance-api"
  },
  "production": {
    "REACT_APP_USERNAME": "MARK ZUCKERBERG from Production",
    "REACT_APP_EMAIL_ID": "MARK@META-PRODUCTION.COM",
    "REACT_APP_API_KEY": "sdklfjhkqhqoiweipjafklnlaksddlkkaskdj-production-api"
  }
}

The keys dev , acceptance and production are totally your choice to name them accordingly. Each of those objects denote different environments.

So technically we have setup the configuration for these three servers.

But how do we know which environment we need to access when, because if you recall our properties.js file has only the variable names mentioned. Nothing about which environment to access from was mentioned.

That's where we use the env-cmd package we installed.

Let's make a small change in scripts part of the package.json file to distinguish between the environments which we want to work on.

  "scripts": {
    "start-dev": "env-cmd -e dev react-scripts start",
    "start-acc": "env-cmd -e acceptance react-scripts start",
    "start-prod": "env-cmd -e production react-scripts start",
    "build-dev": "env-cmd -e dev react-scripts build",
    "build-acc": "env-cmd -e acceptance react-scripts build",
    "build-prod": "env-cmd -e production react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }

What are these now?

Lets break down start-dev script.

Previously it used to be just start so that you could do npm start to do the development in your local.

Now that we have different environments setup, we might need to work on one at a time to test everything is going correct or not.

"start-dev": "env-cmd -e dev react-scripts start" means,

start-dev: your actual script to run in the terminal.

It uses env-cmd package

-e : you are going to specify the environment.

dev : This is the environment name that you actually used in .envcmdrc.json file.

react-scripts start: default starting script.

That means your are running your application in your local with environment variables of dev server.

This way it is self-explanatory what the remaining scripts do.


That's it. Now you don't need to maintain multiple .env files to select your environment variables.

The output for dev when you run the respective script will be:

image.png

Similarly for Acceptance

image.png

And Production

image.png

image.gif

Bam!!! That's it folks.

If you are here yet, make sure you leave a comment below if you liked or you got any feedback for my writing. Will appreciate that.

Thank you for the read. 😊