51

Disclaimer: I am a React noob so perhaps what I am trying to do is not the React Way

I am writing a React front-end that will be deployed to be served statically by some cloud provider, e.g. S3 or Google Storage or whatever. This front-end interacts with several API servers that live somewhere in the cloud, maybe in the same provider, maybe not. Furthermore, while developing the UI or part of it, those servers' addresses might be local or testing instances.

How do I inject the API server(s) URLs into my react application in a flexible so that I can deploy in dev, staging or prod using different addresses?

SOLUTION: I finally ended up using a combination of solutions proposed:

  • use .env.production and .env.development files (exact names) to store the variable REACT_APP_API_URI = 'host'
  • this is automatically picked-up by create-react-app's build scaffolding and available in UI code as process.env.REACT_APP_API_URI

Note this somewhat goes against principles from 12 Factor Apps, e.g. storing env variables in files in version control but it does the job ATM.

4
  • 3
    I usually add a .env.sample to the repo not the actual files with values. Also, you can probably set that environment variable in your CI/CD to better align with the 12 Factor approach. Commented Feb 4, 2019 at 18:33
  • Nice solution. You can use console.log(process.env.NODE_ENV) and console.log(process.env.REACT_APP_API_URI) to watch from any place after adding .env.production and .env.development files to root dir. Commented Jul 7, 2019 at 23:22
  • 1
    Important note: With create-react-app, you need to prefix REACT_APP_ to the variable name to be able to access it. Commented Apr 12, 2021 at 13:03
  • Don't forget to restart your app for the var to take effect, Ctrl-C to Terminate batch job (Y/N)? y, then npm start. I couldn't figure out for the life of me what I was missing Commented Nov 3, 2022 at 0:15

7 Answers 7

26

You can try this:

// http.js
const getBaseUrl = () => {
  let url;
  switch(process.env.NODE_ENV) {
    case 'production':
      url = 'https://stackoverflow.com';
      break;
    case 'development':
    default:
      url = 'https://google.com';
  }

  return url;
}

export default axios.create({
  baseURL: getBaseUrl(),
});
Sign up to request clarification or add additional context in comments.

5 Comments

but process.env.NODE_ENV assumes there is a node server runninng, isn't it? Which means this works at runtime, not at build time.
So you mean webpack introspects the JS code and statically replaces those variables with their value?
Yes. I bet you use create-react-app. When you deploy it as production, you will build the bundle, and NODE_ENV will set to 'production' and your api url will be stackoverflow.com instead of google.com
@GiangLe you did not mention which file we need to have the content of your answer
4

Using this package https://github.com/toddbluhm/env-cmd you could create an env file for your environment

for example create .env.staging and .env file with this code

// .env.staging file   
API_URL=https://staging.url.com/api/
// .env file
API_URL=https://url.com/api/

How to fetch with API_URL from env variable:

fetch(process.env.API_URL)

Then you can just add some extra scripts in your package.json:

{
  "scripts": {
    "build:staging": "env-cmd .env.staging yarn build",
    "build:prod": "env-cmd .env yarn build"
  }
}

2 Comments

But the .env file is read at runtime? When is the process.env.API_URL variable defined? I want this to happen at build/deploy time so that when the app executes in the browser it is statically configured with the right URL.
No, it will transform process.env.API_URL when you run a command that include it. For example if you run command yarn build:staging to build react, it will transform fetch(process.env.API_URL) to fetch('https://staging.url.com/api/') and then you can deploy build files to the staging server.
3

You can use .env file if the API's are constant for development or production environment. after build you can't change these parameters.

If you want to change the URL after build, add a js file lets say config.js

Include the conf.js in index.html

Add URL in conf.js like

var URL1 = 'https://www.google.com'

You can access the parameter like :

export const {URL1} = window;

2 Comments

But f we do this, then URL1 will be publicly available. Anyone can see it.
Yes, Its not a good practice. There must be a back end server which hosts reactjs app. So that you can hit the server using route name, not using ip and port, IP, port will be same as reactjs apps. Then you can get the data from your desired applications from the server side.
2

You can do that making use of environment variables on the build step for example.

You can use something like .env that allows you to define environment variables and load them on your webpack file for example (assuming you use webpack). But you can really use it with any bundler.

.env file:

API=http://localhost:3000

On your webpack you could make use of the DefinePlugin

example taken from docs: add your API env

    ...
    require('dotenv').config()
    ...

    new webpack.DefinePlugin({
      API_ENDPOINT: process.env.API,
      PRODUCTION: JSON.stringify(true),
      VERSION: JSON.stringify('5fa3b9'),
      BROWSER_SUPPORTS_HTML5: true,
      TWO: '1+1',
      'typeof window': JSON.stringify('object')
    });

Anyway, this is just one way. I like this way because it makes my project ready for defining API keys and other useful stuff for different environments.

NOTE: You can even define different .env files for local, staging and production and load the respective one in the webpack depending on the build type.

4 Comments

This makes sense but I have used create-react-app to scaffold my application and it does not seem to use webpack. Or is it using it under the hood?
@insitu yes it does use webpack under the hood. it uses react-scripts.
@insitu look at this post: medium.com/@tacomanator/… it is basically my approach and uses CRA
This is confusing: Are process.env.XXX available at build-time?
0

After creating the .env file. Please restart the app. Like in reactJs use npm start command to restart it. It will work fine.

Comments

0

in the app.js file you can create function of this type sessionStorage.setItem("apipathurl","http://localhost:3000/api")

sessionStorage.setItem("apipathurl","https://example.onrender.com/api");

and call this function each file of your app as in login.js

const baseURL = sessionStorage.getItem("apipathurl");

call this baseURL into your API endpoint

const response = await fetch(${baseURL}/user/login, { method: 'POST', body: JSON.stringify({ email, password }), headers: { 'Content-Type': 'application/json', }, });

this is the the way to create live url path for your app

1 Comment

remarks // this is for reactjs and node js
0

create a config file

const baseURL =
  process.env.NODE_ENV === "production"
    ? "https://webserver.com/api"
    : "http://localhost:3000/api";


    const Config = async () => {
        return (
          <>
          </>
        );
      };
export default Config;
export { baseURL };

import this file in the code

  import { baseURL } from './config';

in api call

  const res = await fetch(`${baseURL}/PATH`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(data),
  });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.