Create-react-app: A way to define custom environment variables

Created on 22 Jul 2016  Â·  60Comments  Â·  Source: facebook/create-react-app

This may be a tiny yet non-obtrusive solution. Allow a custom .env.js file that exports a key value pair used for custom webpack defines. I guess this wont be useful for many, since you any way get to refer to NODE_ENV but I also used this for defining a publicPath from an environment variable or defaulting to root. (useful for me as i had to run the same app for multiple quizzes, so I could build the frontend without configuring anything and having sane default not-get-in-the-way configs while development and testing)

proposal

Most helpful comment

I might have one. Let's say there is api server running at different enviroments like so:

  • dev.api.foobar.com
  • prod.api.foobar.com

And I'm building SPA which supposed to use CORS and being hosted anywhere, just like static site.

And such I want to supply dev/prod absolute paths for different versions of SPA.

Hope this makes sense.

All 60 comments

Can you please clarify your use case in a little more detail? I'm specifically interested in the problem you were solving (configuring for multiple quizzes?) than the exact proposed solution.

I might have one. Let's say there is api server running at different enviroments like so:

  • dev.api.foobar.com
  • prod.api.foobar.com

And I'm building SPA which supposed to use CORS and being hosted anywhere, just like static site.

And such I want to supply dev/prod absolute paths for different versions of SPA.

Hope this makes sense.

I think at that point you have a very advanced use case and ejecting is the way to go. I don't think adding .env support by default is really necessary, since most users will never need it?

@mxstbr Yes may be true, but I just wanted to open this for some discussion, please feel free to close it.

I try to explain my use which is somewhat similar to @dmi3y's usage:

  • I have a quiz app
  • I deploy it to multiple subpaths inside one domain, as in one on /quiz1 and other on /quiz2
  • This is easy using an environment variable based config of publicPath and I use that also in the .env.js file so that it is accessible to the main app.

Basically the .env.js file can act as a way to preprocess any constants without having to include any file in the main app. So for example if we are going to use homepage of package.json, we can include package.json in the .env file and export the constants after a little modification also. However if we do this in the main app, it is not preprocessed and package.json will be included in the app bundle also. While not an issue here because it would be anyways minifed, it will be an issue when we have to use a node module for generating a constant and thus bundle size may increase or it may not work

This is an advanced use case but not a obtrusive solution (not needed but can be provided kind of thing).

I hope this explains clearly the purpose.

Yes may be true, but I just wanted to open this for some discussion, please feel free to close it.

Absolutely no fault in that, we're definitely not saying create-react-app is perfect by far! Discussions like these could open our eyes to use cases we haven't though of, they're incredibly important.

I'm not sure I fully understand your use case, wouldn't you need access to the webpack config anyway if you're changing the publicPath?

@mxstbr not as per https://github.com/facebookincubator/create-react-app/issues/21 where it would be automatically understood from package.json's homepage

Something I missed when trying create-react-app in a cloud9 free workspace was the ability to set a custom IP and PORT for the server to listen to.

I was able to achieve that by manually changing thestart script in react-scripts, but I think using environment variables for that would be much simpler, even more for begginers.

^ That's also my use case.
I need to adjust the ip/port for usage on Cloud9.

I'm curious, can you explain how the workflow works with cloud9? Do you have the developer server running in the cloud and use their browser text editor to edit the code? Where do you see the terminal output? Why not develop locally?

I mainly use this kind of service (Cloud9, Nitrous.io, etc...) when I'm at work and don't have access to my PC.

They're also a good place to study with friends, since they allow collaborative coding. Plus, somewhere free to showcase a small app?

And yes, you use their browser text editor to edit the code and there's also a terminal emulator in the text editor.

One use case I often have for environment variables is when I want to run some code in production but not in development. For example, if you're using an analytics service, you might not want to log any analytics from development versions of the app. Or if you use an external service to sign people up for a mailing list, you don't want your test accounts getting in there.

About Cloud9, one situation I see it adopted more and more is for education. If you're teaching a class of people how to use some technology, you don't want to spend a ton of time making sure everyone has their development environment set up. If you can just give them one Cloud9 config they can get going quickly. So it would be pretty nice to support Cloud9. They also just got acquired by Amazon to be integrated into AWS, which is another sign this sort of thing is going to grow in popularity.

One use case I often have for environment variables is when I want to run some code in production but not in development.

We currently already allow this with process.env.NODE_ENV checks. This is how React determines which code path to use.

So it would be pretty nice to support Cloud9

Absolutely agree. I just want us to learn more about different use cases first, and approach the problem holistically, rather than add flags one by one over time. A holistic solution might turn out to be simpler.

One use case I often have for environment variables is when I want to run some code in production but not in development.

We currently already allow this with process.env.NODE_ENV checks. This is how React determines which code path to use.

Hmm good point. Here's a slightly different example - let's say your app accesses a Firebase backend. There is one that's only used for production, but each developer has their own for local development, so you can stick random experimental stuff in your database without it borking other peoples' environments. One pattern I would use for this is to check an environment variable to get access info for the backend, and have a startup script for development mode that grabbed this from a config file that isn't checked into source control. Is there currently a straightforward way to do this within a create-react-app-created app?

Maybe I'm missing something here, but what about defining two different scripts in your package.json?

{
  "dev": "SOME_ENV_VAR='development' npm start",
  "prod": "SOME_ENV_VAR='production' npm start"
}

and then I think in your app you could have a constants.js file that exports some commons env vars like that URL:

if (process.env.SOME_ENV_VAR === 'development') {
  // export different stuff here
} else {

}

Not 100% sure how a .env file would make that easier?

The problem I encountered is that IP and PORT are hard coded on the start script, which isn't exactly in the app code.

So just defining some environment variables before running the server is not enough.

Maybe I'm missing something here, but what about defining two different scripts

This _currently_ won’t work because we don’t pass _all_ ENV variables to DefinePlugin. We only pass NODE_ENV. We could, however, pass all variables! (This doesn’t seem super problematic to me, and maybe it’s even the right thing to do.)

The problem I encountered is that IP and PORT are hard coded on the start script, which isn't exactly in the app code.

We definitely wouldn’t be hardcoding them when we get to solving this problem. I’m just saying I want to approach this holistically and not just add a bunch of variables one by one without any cohesive system.

Let’s figure out a generic enough system that lets us configure create-react-app for many scenarios: custom port, serving from cloud9, customizing environment, etc.

Sometimes, like with Code-Push, you have additional constellations like this:

| App | Code-Push Deployment |
| --- | --- |
| DEV | STAGING |
| PROD | STAGING |
| PROD | PROD |

So you would need another ENV variable like CODEPUSH_ENV. So yes, @gaearon I agree we should just throw all the env strings into DefinePlugin. In fact I'd go so far and say that should be the default behaviour of DefinePlugin ;)

Does DefinePlugin dumps all the environment variables in a js object in the generated output or does a find/replace of all of them?

There are a lot of very sensitive information in environment variables from a security perspective, this is a big attack vector and we don't want to dump it all by default.

It does a find and replace. Not only is that important for security, it also ensures that dead-code-elimination works properly after the environment variables are set.

On the other hand, I would probably not want any npm module I install to be able to expose any of my environment variables, that seems like an auditing nightmare. My inclination would be to do NODE_ENV for all modules (including npm) but maybe do custom environment variables only in application code.

We could choose a namespace, like REACT_APP_ENV.

Maybe this could be solved instead with dynamic imports - if you do something like

let env;
if (process.env.NODE_ENV == "production") {
  env = require("production-env.js");
} else {
  env = require("development-env.js");
}

then you could get the effect of environment variables without needing changes in the current runtime.

@lacker the problem is that NODE_ENV is effectively reserved for optimisation. You can't use anything other than NODE_ENV.

I once built an app for one client, and ended up deploying a second identical copy of the app for a different client. The only difference between the two deployments was the company names and branding colours. To do this, I just defined environment variables for each of those features. The issue is that those features vary between different clients, not between development and production.

@gaearon I don't like the idea of a prefix. It feels awkward to have to prefix all the variables with something that has nothing to do with my app, and counter-intuitive that some variables pass through and others do not.

Can we use npm config for specifying variables like port, proxies, etc (need to figure out a list of them), as well as exposing custom options to the app? The nice thing about it is it can be specified right in package.json, there’s a CLI to change it, and you can have local overrides or use environment variables... It seems.

By the way I’m coming to the conclusion that specifying ports, proxies and stuff is fair game because we’re competing for system resources. We just need to make sure the defaults work well with zero configuration, but some optional config for shared resources like ports is fine.

I'd suggest for port number we should just use process.env.PORT || 3000, which is pretty much the standard in node.js. It's what platforms like heroku support.

Port would only be relevant for local development, wouldn’t it?

The reason I’d like to avoid envs by default is that you can’t easily write scripts that use them in a cross platform way. So somebody publishes a react-example that contains PORT=3001 react-scripts start, and then somebody else tries this on Windows, and it doesn’t work. Now they can’t learn React from this example. A solution to this is to use a package called cross-env (or to extract a script and set the process.env.PORT yourself there) but this is not a very common knowledge.

So I would prefer config in package.json because it is cross-platform “by default” but you can _also_ specify envs to override it if you really want to.

For those of you who just needed PORT, you can specify it as an environment variable in the next alpha. Please try it out: https://github.com/facebookincubator/create-react-app/pull/190.

This is not related to this issue so keeping it open.

Neo solves this using an env namespace, like @gaearon proposed. I think that would be preferred over setting config in package.json since some items may be environment specific, and others may have needs for access of sensitive data which should not be committed.

Thanks for the insight! Has this been working well for your users?

@gaearon yes, we have a few different projects that utilize custom namespaced environment variables. I'll open a PR and we can evaluate its merits.

I am in favor of passing env to DefinePlugin. In our use case we end up swapping out a bunch of different service urls. Writing code like:

if (process.env.NODE_ENV === 'development') {
  // export different stuff here
} else {

}

to do something that environment variables solve seems suboptimal.

@unscene

Support for custom variables has been implemented in #342. It will be released in 0.3.0.
Support for NODE_ENV has been in Create React App since the very first version.

Sweet that sounds great.

As for NODE_ENV I saw it were there just didn't think it was the way to go.

Dig the name-spacing solution though.

Took me half an hour to find out this:
To set a different port for create-react-app you have to create ".env" file in project root directory and set the port like this:
PORT=80

@thg303 and posterity, note that to use a port below 1024, you'll need to sudo your react-scripts start command.

@thg303 Did it work for you _just_ by adding the .env file with the env variable? I'm having trouble getting that to work.

@eric-khoury I just test it for changing the port number. I have no idea for other env variables.

@eric-khoury Please note that only env that starts with REACT_APP_… available in your app. Every other envs (such as PORT) only available in build process

@dvkndn Thx for the info, I missed that part completely.

Simple question @all, how can we inspect the value of NODE_ENV in the front-end React code? I assume this is passed to the front-end given this conversation?

Is there a way to set a default NODE_ENV on the server as well? Perhaps by editing the .env file? I assume you have to npm run eject to do that? Or not?

You could always just alias it with the REACT_APP_ prefix if it's not available


From: Operations Research Engineering Software+ notifications@github.com
Sent: Dec 12, 2016 9:53 PM
To: facebookincubator/create-react-app
Cc: Ryan Fairchild; Mention
Subject: Re: [facebookincubator/create-react-app] A way to define custom environment variables (#102)

Simple question @allhttps://github.com/all, how can we inspect the value of NODE_ENV in the front-end React code? I assume this is passed to the front-end given this conversation?

-
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/facebookincubator/create-react-app/issues/102#issuecomment-266621353, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AADdT4RzoEf5ogcwNpKbKnzb05z034rtks5rHgi0gaJpZM4JTJJ0.
This e-mail message, and any attachments, is intended only for the use of the individual or entity identified in the alias address of this message and may contain information that is confidential, privileged and subject to legal restrictions and penalties regarding its unauthorized disclosure and use. Any unauthorized review, copying, disclosure, use or distribution is strictly prohibited. If you have received this e-mail message in error, please notify the sender immediately by reply e-mail and delete this message, and any attachments, from your system. Thank you.

@ORESoftware could you use console.log(process.env.NODE_ENV)?

@ORESoftware you have to set NODE_ENV via os environment variable. in linux it would be like executing this command in the terminal:
NODE_ENV=production && npm run build

@thg303 thanks, I got that part :) what I am not sure of, is if this value* is sent by create-react-app or if I have to do that manually. *or any other env values besides NODE_ENV

If it is sent to the front-end, how can I access the value for NODE_ENV on the front-end sent from the backend?

Basically looking to render things differently depending if I am dev or prod, etc.

Simple question @all, how can we inspect the value of NODE_ENV in the front-end React code? I assume this is passed to the front-end given this conversation?

Have you had a chance to read the corresponding section in the User Guide? It specifically answers this question with an example. TLDR: it’s process.env.NODE_ENV. It is replaced at the build time so you get "development" on npm start but a production bundle created with npm run build will hardcode this to "production".

If it is sent to the front-end, how can I access the value for NODE_ENV on the front-end sent from the backend?

You can't "send" it from backend. If it's on the backend, your app is already compiled in production mode, so it's "production".

you have to set NODE_ENV via os environment variable. in linux it would be like executing this command in the terminal:

This answer is incorrect. With Create React App NODE_ENV is hardcoded depending on whether you used npm start or npm run build. You can't override it (precisely because people sometimes override it wrongly and end up with bloated builds since they get a slow development version of React). However you can specify REACT_APP* variables, as described in User Guide I linked to above in this comment.

@gaearon so basically in short, you can do:

REACT_APP_NODE_ENV=development

and on the front end, we have:

const nodeEnv = window.REACT_APP_NODE_ENV`   // (likely incorrect) 
 ```

but looking at the link, you sent, it looks like:

```js
render() {
  return (
    <div>
      <small>You are running this application in <b>{process.env.NODE_ENV}</b> mode.</small>
      <form>
        <input type="hidden" defaultValue={process.env.REACT_APP_SECRET_CODE} />
      </form>
    </div>
  );
}

that would mean that instead of

const nodeEnv = window.REACT_APP_NODE_ENV`   // front-end

instead on the front-end we have

const nodeEnv = process.env.NODE_ENV`      //front-end

It's a little counterintuitive to have Node.js related stuff on the front-end, but I guess that's pretty normal now that we are using Webpack etc. We have to use surrogates for some of the backend code (like process, fs, etc).

thanks

@ORESoftware

No, NODE_ENV is the built in one. It's the only variable that is available by default and it doesn't need REACT_APP prefix. You read it like this:

var env = process.env.NODE_ENV;

As I already mentioned, User Guide contains an example that specifically shows this. I recommend giving it another look.

For any custom variables, you'd use REACT_APP prefix. But NODE_ENV is built-in, doesn't have a prefix, and you can't specify it yourself—its value depends on whether you're in development or a production mode.

Please refer to the section in User Guide, I'm just repeating what it says here.

@gaearon ok I just read what you wrote, np. However the user guide does not seem to demonstrate how to access the variables in the front-end, at least not in the same section (tell me if I am wrong :)

I have this

 "start-dev": "REACT_APP_NODE_ENV=development && react-scripts start",

on the front-end

if I log process.env, I get an empty object. So I am _guessing_ that instead of doing

process.env.REACT_APP_NODE_ENV

it will be

window.REACT_APP_NODE_ENV

I will test it out, but if it's it not in the docs yet, I would be happy to add whatever the right way to do this is.

e.g. window.R = no search results

screenshot from 2016-12-13 14-28-27

I just filed a new issue for this, sorry if it's my misunderstanding

https://github.com/facebookincubator/create-react-app/issues/1266

As I wrote in the other two comments (https://github.com/facebookincubator/create-react-app/issues/102#issuecomment-266881171 and https://github.com/facebookincubator/create-react-app/issues/102#issuecomment-266710152) you don't need to specify NODE_ENV or use REACT_APP prefix for it. It is already available exactly like I show in the snippet above:

console.log(process.env.NODE_ENV);

You don't need anything else for it to work.

Do you have any problems getting this one working?

I think looking at the source might help anyone

https://github.com/facebookincubator/create-react-app/blob/92d9cda964b920b494774694cc9cef2f216e3cb4/packages/react-scripts/config/env.js

that url might get old, but that's the idea

Shouldn't it be possible to edit vars at runtime using the dev settings?

fwiw - here's what I did for this:

  1. set up script in package.json to run like this:
    "build_app": "REACT_APP_MY_VAR=$MY_VAR react-scripts build",
  2. then when you run the script like this: MY_VAR=foobar npm run build_app
  3. now you can access foobar inside your js via process.env.REACT_APP_MY_VAR

Above works for dev process as well.

Sorry, I know this is closed, but I was wondering if CRA can be set up to use a custom .env file? I have three different environments my app will run on: dev, staging, and production. dev and production are covered, but right now it doesn't seem like there's any easy way to have separate environment variables for other stages.

It would be handy if an additional environment variable could be specified to select the custom .env file, and use the default .env files if the additional variable is undefined.
e.g. (in Windows)
start: react-scripts start - uses .env.development
build_staging: "set REACT_APP_ENV=staging & react-scripts build" - uses .env.staging
build: "react-scripts build" - uses .env.production

I'm not sure if this is too advanced a use case, but it seemed like having multiple stages of development with different environments each might be quite common.

I was just reading through this thread, because I needed the same thing (.env and .env.production), however I have an ejected version of CRA and noticed this was already changed at some point to work as @Baldeep and others have wanted (I think)

https://github.com/facebookincubator/create-react-app/blob/next/packages/react-scripts/config/env.js#L28

I think this is what some are looking for, right?

@bradwestfall Kind-of, NODE_ENV is set by CRA, and can't be changed in a non-ejected project (since the last time I checked).

My suggestion for a change would be to check if an environment variable called REACT_APP_ENV exists, if it does, then use that environment variable when setting up dotenv, otherwise default to NODE_ENV like it does just now.

I was just reading through this thread, because I needed the same thing (.env and .env.production), however I have an ejected version of CRA and noticed this was already changed at some point to work as @Baldeep and others have wanted (I think)

Yes, support for .env.production and similar was added in https://github.com/facebookincubator/create-react-app/pull/1344 as part of 1.0.0.

@Baldeep Sorry we didn't make it clear. If you just use .env.production it already works, you don't need to do anything else. It's documented right here:

screen shot 2018-01-18 at 13 17 14

I will lock this thread to prevent further confusion.

Oops, I misread your message @Baldeep. You're right production, development is covered, but staging is not. However continuing this discussion in a closed thread is not productive: people who find it keep +1'ing it but people who maintain this repository don't look at closed threads (we have enough open issues to worry about).

So if you feel this is useful please file a new issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Aranir picture Aranir  Â·  3Comments

stopachka picture stopachka  Â·  3Comments

onelson picture onelson  Â·  3Comments

xgqfrms-GitHub picture xgqfrms-GitHub  Â·  3Comments

JimmyLv picture JimmyLv  Â·  3Comments