DEV Community

Matt Catalfamo
Matt Catalfamo

Posted on

Runtime Configurations with React

Most of the time using custom build time environment variables are suitable but runtime variables can be valuable in addition to or in place of environment variables.

Runtime configurations or variables, can be beneficial when you need to change a configuration at run time. Some examples of variables you could load at runtime is theme data or api urls.

Do not store any secrets (such as private API keys) in your environment or runtime variables!

Why runtime variables?

  • Build app only once and deploy the same build to multiple environments (i.e. dev, qa, prod)
  • Configurations can be changed/updated after the app is deployed
  • Load configurations from an external source
  • Save time - Build pipelines can take long periods of time some with many steps (i.e. infrastructure steps, build steps, tests, etc). Loading configurations during runtime can help reduce the amount of times your app is built.

How do runtime variables work?

Runtime variables get loaded into the browser's window object when the index.html of a single page application gets loaded.

In the <head> or <body> of the html file we can run a Javascript snippet that sets up the configurations on the window object.

Javascript code in the index.html file will get loaded synchronously from top to bottom as long as the async flag is not present. By placing the code to load our snippet before the main bundle it can be guaranteed that the values will be set on the window object and accessible when your main javascript bundle is loaded.

Let’s look at how this can be accomplished.

Create a new file called runtime-config.js and setup some variables

// runtime-config.js
window['runConfig'] = {
    apiUrl: 'test.com/api'
}

To load the script in the index.html file add the script tag to the file inside either the <head> or <body> tag. If you are starting with Create React App the file will be located at <project_root>/public/index.html

<script src="%PUBLIC_URL%/runtime-config.js"></script>

// index.html
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">

    <!-- runtime config -->
    <script src="%PUBLIC_URL%/runtime-config.js"></script>
    <!-- runtime config -->

    <title>React App</title>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
  </body>
</html>


How to use in a React component

To access the variables that are setup in the runtime-config file, from your app files you can reference the window object.

window['runConfig']

Example usage in a React component:

export const MyComponent = () => {
  const { apiUrl } = window['runConfig'];
  return (
    <div>Runtime config apiUrl: {apiUrl}</div>
  )
}


Full Example:

https://github.com/mattcat10/react-runtime-config

Notes:

  • Don't use runtime configurations if your configurations are really large. They are loaded synchronously and could slow down your initial load time of your app

  • This post explains how to use runtime configurations in a react app, but the same concept can be applied to any SPA framework.

Oldest comments (10)

Collapse
 
ponder6168 profile image
ponder6168

Solved my issue. Thanks!

Collapse
 
hey_yogini profile image
Yogini Bende

Is there any way, to use this same configuration for local setup? This worked for runtime but localhost could not find them!

Collapse
 
matt_catalfamo profile image
Matt Catalfamo

Hey,

If you are using webpack, in your local webpack configuration you can create the file using the create-file-webpack plugin (npmjs.com/package/create-file-webpack)

Then your plugin configuration would look something like this:

plugins: [
  new CreateFilePlugin({
    path: `your public folder`,
    fileName: 'runtime-config.js',
    content: `window.runConfig=${JSON.stringify(
      {
        apiUrl: 'test.com/api'
      }
    )};`,
  }),
]

And if you wanted to load your config from a file you can import it like:

const myConfigVar = require('./your-config.json');

and replace { apiUrl: 'test.com/api'} with myConfigVar

Collapse
 
idjuradj profile image
idj

Great article! Do you have any advice on how to make these variables specific per environment?

Collapse
 
matt_catalfamo profile image
Matt Catalfamo

Thanks for the reply. Considering that these are runtime configs, one method you can use is creating the runtime-config.js file as part of the deployment pipeline.

I like to keep the config files per environment organized in json in my repository, so one method that I like to use is to have a different json file per environment (dev.config.json, stg.config.json, prod.config.json) making sure the file name is the same as the environment name and keeping the property names consistent

Ex dev json:

{
  "apiUrl": "testing.mattcat.dev"
}

Enter fullscreen mode Exit fullscreen mode

Ex prod json:

{
  "apiUrl": "prod.mattcat.dev"
}

Enter fullscreen mode Exit fullscreen mode

Then during the deployment pipeline as a step, calling a bash script to read in the proper environment json file and create the runtime-config.js file.

The bash script looks something like this:

#!/bin/sh -e

CONFIG_BASE_PATH="./app/configs"

touch "./app/env-config.js" # create generic file
ENV_CONFIG=$(node -p -e "JSON.stringify(require('./${CONFIG_BASE_PATH}/${BUILD_ENV}.config.json'))") # read proper json file

echo "window.envConfig = $ENV_CONFIG" >> "./app/env-config.js" # write json to generic file

Enter fullscreen mode Exit fullscreen mode

Calling it like this during your deployment pipeline
BUILD_ENV=stg ./config-expansion.sh

I am sure you can find other ways to generate the run-config.js file but this is one method that has worked for me in the past.

Collapse
 
priya0607jain profile image
Priya Jain

Thanks for the great article! Finally, after days of headache, it helped me understand the things about "build once, deploy everywhere".
Just one thing though, as @idjuraj suggested below, on making variables specific per env, you said during the deployment pipeline as a step, calling a bash script to read in the proper environment json file and create the runtime-config.js file., can this be also applied to when we push the code to pipleine? I mean, I have a git pipeline that automates the build process as soon as the code is pushed. So is there any way that I can define the environment into that pipeline (Inside the yml file) ? So that build can be created automatically for different envs?

Collapse
 
adash profile image
Adam K

Thanks Man!
This is exactly what I needed!

Collapse
 
amanchaudhary1998 profile image
AmanChaudhary1998 • Edited

Can you help me how to configure for dev, prod and staging at the runtime and how BUILD_ENV get the environment variable

ENV_CONFIG = ${node -p -e "JSON.stringify(require('./${CONFIG_BASE_PATH}/${BUILD_ENV}.config.json'))")

Collapse
 
mahdigb05 profile image
el mehdi benmoumen

thanks for the article !!, I only have one question I tried this methode but had a small issue. when I open a new tab (when clicking a link for example) the scripts doesn' get executed and would have undefined error when trying to read the config object.

Collapse
 
joe_black_4752a0e6d658ff5 profile image
Joe Black

Does anybody have tips on testing this with Jest?