Difference in environment variable usage between development and production modes? - node.js

I'm learning how to deploy a simple backend node.js project to production, in my case heroku. I came across this note regarding environment variables in a .env file:
The environment variables defined in dotenv will only be used when the backend is not in production mode, i.e. Heroku.
We defined the environment variables for development in file .env, but the environment variable that defines the database URL in production should be set to Heroku with the heroku config:set command:
heroku config:set MONGODB_URI=mongodb+srv:...
How can my .env file use the heroku config:set MONGODB_URI=mongodb+srv... environment variable, if using heroku would mean that my backend is in production mode? The first sentence states that environment variables are only used for development mode.
What am I understanding wrong? Are environment variables used in both development mode and production mode, and the wording of the note I read was wrong?

I think it's saying that environment variables in .env will be used when you're in development (not Heroku) and that if you do want to use your environment variables in Heroku that you need to do it through heroku config:set ....

What am I understanding wrong? Are environment variables used in both development mode and production mode, and the wording of the note I read was wrong?
Environment variables are used in all scenarios, but only in local development mode they are read from a file.
dotenv is a package that allows reading environment variables from a file.
In production mode, what Heroku is essentially doing is this, for example:
PORT=9999 node index.js
Try it, you can access this variable inside Node by using:
console.log(process.env.PORT);
// 9999
Environment variables are just global variables available to the entire process.

Related

When I use my Heroku Config Variables in my react app, they come back as undefined

I've built a simple resume website using react; hosted on heroku, its code can be found here. I am using a service emailjs to allow others to reach me via email. Locally I am using config/secrets.json to load variables I need to initiate the emailjs object. I added all variables contained in config/secrets.json to my heroku app located at Settings Config Vars.
You can see how I attempt to access those environment variables here.
When I take a look at the console, I see that process.env.INIT_USER outputs undefined? I have INIT_USER in my heroku app and see it on the cli with command heroku config -a app_name.
I cannot access my environment variables despite the fact that I see them on my herokus app settings.
My application is deployed in Heroku and I use Heroku Pipelines for my deployment and build process.
If you set the ENV vars in heroku after deploying the app, try redeploying the app.
With a create-react-app app (which uses buildpack), I found that the process.env variables were set during the build phase of the deployment. So, updating the variables in the heroku dashboard after the build was completed did not update the variables in the process.env object. Redeploying the app updated the process.env object with the env variables I had set.
This also causes problems with pipelines because Heroku does not rebuild the app slug when you promote it to production. This means the promoted app will use the process.env variables from your staging app, so you have to make sure your staging app has the same variables that you want to use in production.
Big design flaw on Heroku's part IMO.
I had to actually uninstall my globally installed create-react-app:
npm uninstall -g create-react-app
and opt for this app generation command instead:
npx create-react-app myapp

Environment variables in NodeJS depenency

Environment variables in NodeJS depenency
I have a NodeJS application which has a dependency of mine
my-base-module: git+https://myuser:mytoken#gitlab.com/organization/my-base-module.git#v1.0.0
I am also using the dependency dotenv, which in development I use the file .env and in other environments I pass the variables through docker environment variables
The problem I have, and I do not know why and how to solve it is that in my-base-module I do not share the same environment variables (and I need it to). It is like the variables loose the reference
require('dotenv').config();
const env = process.env.NODE_ENV;
for example in that bit of code the NODE_ENV variable inside my-base-module is undefined. However in the container is defined and with the right value
Update 1
I am requiring dotenv in both my-application and my-base-module. If I enter to the container and I do $ echo $NODE_ENV. I get production.
If my application process.env.NODE_ENV also holds production. But in the dependency process.env.NODE_ENV is undefined
I will try to do some github repositories to reproduce it
I was wrong, this works I made this small POC with these public repositories
https://github.com/agusgambina/try-base-module..https://github.com/agusgambina/try-application-dotenv
https://github.com/agusgambina/try-application-dotenv

Node js express project how to add environment variables

I am a java script full stack developer.
In the vue js I create two files in the root.
env.development
env.production
In my main.js file, I can access environment variables like this
process.env.VUE_APP_MY_VARIABLE_X
How production and development differs in the vue js is,
if I use npm run serve project loaded the development environment variables. If I use npm run build it takes production environment variables. That's all in vue.
But in my expressjs project,
"start": "nodemon server.js --exec babel-node -e js",
This command will always responsible for the run project. I couldn't find two commands like in vue. I go though the tutorials every body says use the package called dotenv.
I couldn't figure out that how could this package identify the environments this is production and this is development.
End of the day I want to set my db password to 123456 in my local machine and root#123456 in the server. How could I achieve this?
Vue.js handles modes automatically, depending on the command (e.g. serve sets NODE_ENV=development, while build sets NODE_ENV=production).
Depending on the mode, it also automatically loads files with variables from disk.
Environment variables in Node.JS
However, Node.JS does not do that by default, and you have to set up your application to handle environment variables.
In Node.JS you can pass variables via the shell command, for example:
MY_VARIABLE=x node myapp.js (by prepending the command with variables), and that will give you process.env.MY_VARIABLE inside your myapp.js application.
Following this behavior, there's a consensus on using NODE_ENV variable for setting up the environment mode.
For production use, you'd start your application using NODE_ENV=production node myapp.js, while for development NODE_ENV=development node myapp.js.
Of course, if your machine already has these environment variables set up (for instance in .bash_profile) you do not need to prepend your command with them.
As a practice, in development machines, you'd have these variables already set up on your machine, while production machines (e.g. docker containers, etc) start clean and you pass the environment variables when starting your application.
For example, Heroku (and other deployment services) allow you to set up environment variables which are set at machine start.
There's also the method of storing variables in files (such as the .env, or other files), but those you'd have to read from disk when your application starts.
And this is where dotenv (and config package) come in play.
What dotenv does, is it reads .env file stored in your application execution path (root of the app), and sets any variables defined there into process.env for Node.JS to use.
This is extremely useful for development machines, but on production it's recommended to not have files that store sensitive information in variables, but rather use system environment variables.
There is also the option, for production machines, to construct or load into the machine an .env file at machine setup time, into the app directory.
Note:
never commit .env or config files that store passwords and sensitive information, to your repository
never store development and production variables in the same file
The dotenv approach
The best way to go about it, would be to use dotenv, and have different .env files, one on your development machine, and a different one on your production machine. That way, when your application starts, it reads the variables that are stored in the adjacent .env. This is the most secure and reliable way, in absence of means to pass environment variables to your production machine from a machine management application/interface.
The easiest way to set up your app with dotenv would be to set your start command to something like:
"start": "nodemon --exec \"node -r dotenv/config\" server.js"
and then in the .env file stored on your local/development machine you'd have something similar to:
DATABASE_PASSWORD=1235
DATABASE_USERNAME=joe-dev
...
and in the .env file on your production machine (server):
DATABASE_PASSWORD=root#1235
DATABASE_USERNAME=root
...
according to my understanding
you don't have created and setup a config file and required it in your app.js or any other file. let see for example create config file
const config = {
"development":{
"host":"localhost",
"dbport":"27017",
"port":"",
"username":"",
"password":"",
"userdb":"",
"passworddb":"123456",
"authSource":"",
"database":"devDB"
},
"staging":{
"host":"",
"dbport":"",
"port":"",
"username":"",
"password":"",
"passworddb":"#123456",
"database":"stageDB",
},
"production":{
"host":"",
"dbport":"",
"port":"",
"userdb":"",
"passworddb":"#123456",
"username":"",
"password":"",
"database":"prodDB",
}
};
module.exports = config;
then you have you setup a variable in your .env file like NodeENV = 'prod'
then import it into your files like
var config = require('./config')["process.env.NodeENV"];
and one more last thing dotenv is only used to loads environment variables from a .env file into process.env.

Using environment variables in Node

I have been trying to get a streamline way of having different environment variables for local and production web apps, but I haven't come across the "ideal" solution yet.
There's the option of having a config.js file like so:
//config.js
{
"secretKey": "SDFDASFFSFD",
"facebook": {
"clientID": "EFGFDGBGDGFS",
"clientSecret": "EGDFNHFG"
}
}
And accessing via ES6 imports
Or using .env files like so:
SOME_KEY=someValue
HELLO=world
FACEBOOK_SECRET=435SDFSF5DZVD7S
And accessing the variables via process.env in the code using dotenv.
Obviously no matter what route you go down, the file will need to be omitted from version control which is fine. Each of these ways are great, but they only seem to work well for local development.
So how do you then have a separate file for a production environment? The dotenv docs say they strongly recommend against a .local.env and .prod.env situation.
Also, how is best to push to a remote server? I have my own server with Gulp tasks which run on a Git post-receive hook. How is best to pass up the production environment variables to here?
Thanks
You could have own config file for each environment:
- environments
- index.js
- deveplopment.json
- staging.json
- production.json
To use appropriate config file, run the app with required NODE_ENV:
NODE_ENV=production node index
In environments/index.js determinate the current NODE_ENV and use config:
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
module.exports = require('./' + process.env.NODE_ENV);
If config file doesn't include secret info (apiKeys, etc), it can be pushed to repo. Otherwise add it to .gitignore and use environment variables on the server.
Note:
For advanced configuration use such packages as nconf.
It allows to create hierarchical node.js configuration with files, environment variables, command-line arguments, and atomic object merging.
Have you thought about having a keys.js file with a .gitignore on it?
I've used this in the past to use module.exports{} to get my variables usable but not going to version control for the security side of things!

Node JS, detect production environment

When I'm in dev mode I don't want my server to send email and some other stuff so I have this in server.js file:
process.env.NODE_ENV = 'development';
When I move it to production i change the value to 'production'.
Problem is of course that it is easy to forget on deployments. Is it possible somehow to detect when server is in production?
If it's not, is it possible to write a batch script that replaces a string in a file?
You shouldn't manually change values of process.env object, because this object is reflecting your execution environment.
In your code you should do the following:
const environment = process.env.NODE_ENV || 'development';
And then you launch your app in production like this:
$ NODE_ENV=production node app.js
If NODE_ENV environment variable is not set, then it will be set to development by default.
You could also use dotenv module in development to specify all environment variables in a file.
Furthermore, I've implemented a reusable module, which allows to automatically detect environment by analyzing both CLI arguments and NODE_ENV variable. This could be useful on your development machine, because you can easily change environment by passing a CLI argument to you Node.js program like this: $ node app.js --prod. It's also nice to use with Gulp: $ gulp build --prod.
Please see more details and use cases on the detect-environment's page.
The suggested way to tackle these kind of problems is by using the process global object provided by NodeJS. For example:
var env = process.env.NODE_ENV || "development";
By the above line. We can easily switch between development / production environment. If we haven't configured any environment variable it works with development environment.
process.env is an object that contains the user environment.
For example if we are running our application in a bash shell and have configured NODE_ENV to production. Then i can access that in node application as process.env.NODE_ENV.
There are multiple ways to define this NODE_ENV variable for nodejs applications:
## Setting environment variable for bash shell
export NODE_ENV=production
## Defined while starting the application
NODE_ENV=production node app.js
So i don't think you would require any batch file for this. When handling multiple configuration variables, follow this.
This is normally handled through configuration files (e.g. config frameworks like node-convict) and through environmental variables. In the start command in production, you might do something like:
NODE_ENV=production npm start
then the process.env.NODE_ENV would be properly set by any module in your app that cares.

Resources