Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A way to define custom environment variables #102

Closed
meghprkh opened this issue Jul 22, 2016 · 60 comments
Closed

A way to define custom environment variables #102

meghprkh opened this issue Jul 22, 2016 · 60 comments
Milestone

Comments

@meghprkh
Copy link

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)

@gaearon
Copy link
Contributor

gaearon commented Jul 22, 2016

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.

@dmi3y
Copy link

dmi3y commented Jul 23, 2016

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.

@mxstbr
Copy link
Contributor

mxstbr commented Jul 23, 2016

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?

@meghprkh
Copy link
Author

@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.

@mxstbr
Copy link
Contributor

mxstbr commented Jul 23, 2016

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?

@meghprkh
Copy link
Author

@mxstbr not as per #21 where it would be automatically understood from package.json's homepage

@d-gubert
Copy link

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.

@tyrbo
Copy link

tyrbo commented Jul 24, 2016

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

@vjeux
Copy link
Contributor

vjeux commented Jul 24, 2016

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?

@d-gubert
Copy link

d-gubert commented Jul 24, 2016

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.

@lacker
Copy link
Contributor

lacker commented Jul 24, 2016

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.

@gaearon
Copy link
Contributor

gaearon commented Jul 24, 2016

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.

@lacker
Copy link
Contributor

lacker commented Jul 24, 2016

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?

@mxstbr
Copy link
Contributor

mxstbr commented Jul 24, 2016

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?

@d-gubert
Copy link

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.

@gaearon
Copy link
Contributor

gaearon commented Jul 24, 2016

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.)

@gaearon
Copy link
Contributor

gaearon commented Jul 24, 2016

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.

@pke
Copy link

pke commented Jul 25, 2016

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 ;)

@vjeux
Copy link
Contributor

vjeux commented Jul 25, 2016

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.

@ForbesLindesay
Copy link
Contributor

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.

@gaearon
Copy link
Contributor

gaearon commented Jul 25, 2016

We could choose a namespace, like REACT_APP_ENV.

@lacker
Copy link
Contributor

lacker commented Jul 25, 2016

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.

@ForbesLindesay
Copy link
Contributor

@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.

@ForbesLindesay
Copy link
Contributor

@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.

@gaearon
Copy link
Contributor

gaearon commented Jul 26, 2016

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.

@gaearon
Copy link
Contributor

gaearon commented Jul 26, 2016

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.

@thg303
Copy link

thg303 commented Oct 26, 2016

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

@tannerlinsley
Copy link

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

@eric-khoury
Copy link

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

@thg303
Copy link

thg303 commented Nov 16, 2016

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

@thien-do
Copy link
Contributor

@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

@eric-khoury
Copy link

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

@ORESoftware
Copy link

ORESoftware commented Dec 13, 2016

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?

@unscene
Copy link

unscene commented Dec 13, 2016 via email

@eliperelman
Copy link
Contributor

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

@thg303
Copy link

thg303 commented Dec 13, 2016

@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

@ORESoftware
Copy link

ORESoftware commented Dec 13, 2016

@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.

@gaearon
Copy link
Contributor

gaearon commented Dec 13, 2016

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.

@ORESoftware
Copy link

ORESoftware commented Dec 13, 2016

@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:

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

@gaearon
Copy link
Contributor

gaearon commented Dec 13, 2016

@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.

@ORESoftware
Copy link

ORESoftware commented Dec 13, 2016

@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

@ORESoftware
Copy link

ORESoftware commented Dec 13, 2016

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

#1266

@gaearon
Copy link
Contributor

gaearon commented Dec 13, 2016

As I wrote in the other two comments (#102 (comment) and #102 (comment)) 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?

@ORESoftware
Copy link

ORESoftware commented Dec 14, 2016

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

@ollyde
Copy link

ollyde commented Sep 12, 2017

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

@jforaker
Copy link

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.

@Baldeep
Copy link

Baldeep commented Sep 25, 2017

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.

@bradwestfall
Copy link

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?

@Baldeep
Copy link

Baldeep commented Jan 18, 2018

@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.

@gaearon
Copy link
Contributor

gaearon commented Jan 18, 2018

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 #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.

@facebook facebook locked and limited conversation to collaborators Jan 18, 2018
@gaearon
Copy link
Contributor

gaearon commented Jan 18, 2018

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests