When working in React projects we have the ability to define and use environment variables putting them in an .env file, to use them in our code we just need to use process.env.REACT_APP_VARIABLE, the problem comes when we build the project, so we can deploy it, when building, React will change all the places where we use process.env.REACT_VARIABLE for the actual value of the variable, once the application is built we cannot change this values, so what happens if you want to have dynamic environment variables and change them on the fly, well you will need to change the variables, build again the project and redeploy. We will change this by defining our variables in a config.json file
First we need to create a new React project
npx create-react-app env-variables
cd env-variables
npm start
Now we are going to create a new file called config.json inside the public folder (./public/config.json), when changing this file or adding new variables remember to validate the JSON syntax. By adding this file to public, once we build and deploy the project this file will be available in http://appurl.com/config.json
{
"REACT_APP_NAME": "Env variables"
}
Next we are going to create a class with some static properties and make them available through all the application, create a new file called config.js inside of src folder
// ./src/config.js
// Class containing all environment variables
export class Config {
// Static properties shared by all instances with default value for environment variable
static REACT_APP_NAME = "Default value";
// Static properties shared by all instances with default value for environment variable
static REACT_APP_AGE = 10;
}
Now we are going to fetch the values on our json file and change the values of the Config class
// ./src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Config } from "./config";
/**
*
* @desc Fetch config.json file and changes Config static properties to the values on the file
*/
const fetchConfig = async () => {
try {
// Fetch config.json
const configFile = await fetch("/config.json");
// Get values as JSON
const coinfigFileValues = await configFile.json();
// Change Config class static values to the values on the file
Object.keys(coinfigFileValues).forEach((key) => {
Config[key] = coinfigFileValues[key];
});
} catch (e) {
console.log(e);
}
};
// Load app after we have fetch the values, this way we avoid race conditions, and we make sure we get the values from the file
fetchConfig().then(() => {
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
});
To use our environment variables we just need to import { Config } from "./config"; and use the value we need for example Config.REACT_APP_NAME, lets add this values to our App component
// ./src/App.js
import logo from './logo.svg';
import './App.css';
import { Config } from "./config";
function App() {
/**
*
* @desc log environment variable
*/
const logEnvironmentVariable = () => {
console.log(Config.REACT_APP_AGE)
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<p>
{Config.REACT_APP_NAME}
</p>
<p>
{Config.REACT_APP_AGE}
</p>
<button onClick={() => logEnvironmentVariable()}>Test</button>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
Now you can change your config.json file and reload the page, the app will load the latest values, you don't need to rebuild or redeploy your app. You can access the server or service where you deploy your app and change your config.json, or you could even save your config.json file in another server or service and access this file changing the url where we do the fetch request
With the current approach we can handle two environments, local which is the default values for the static properties on the Config class and another environment which are the actual values on the config.json file. To handle multiple environments we have multiple solutions and everything depends on how you deploy your app, in my case I use GitHub actions to generate this file for me depending on the environment, you could change the url where we fetch the config.json file to change depending on the environment and have multiple json files for example config-dev.json config-stg.json, or you could add a script to change you json file after the npm run build command
Don't add sensitive data to the environment variables it does not matter which approach you use this one or using the .env files, the values of your variables are visible to everyone and exposing sensitive information like credentials can lead to security risks, if you need to access restricted services or manipulate sensitive data do it on the server or back end instead
In this repository https://github.com/obravocedillo/EnvVariablesJSON you can find the code.