Setup multiple .env configurations (React/Next/Node) - node.js

How to use multiple .env config files correctly for development / stage / production. I realize I need a .env file, use dotenv (at least), but when I start hosting my app (React), I use localhost: 5000 urls, but I have to use some service-host urls which I use.

Your .env file is not commited.
So on you production build, you will configure your .env file to contain your production details. Again, .env files are private.
Your development .env file will contain details that you use for your localhost.
You can also, set a variable called to say PROD_BASEURL and then utilize an IF statement in your code.
if(PROD_BASEURL) {
do stuff
}
To answer your question. No, you won't use multiple .env files to separate PROD/UAT/DEV

Why do you want to use multiple .env files ?
The general recommendation is to have one unique .env file.
Should I have multiple .env files?
No. We strongly recommend against having a "main" .env file and an
"environment" .env file like .env.test
link : https://github.com/motdotla/dotenv#should-i-commit-my-env-file
Use a package like dotenv to manage your env variables. There are other package that do the same thing.
And you define your production env variables on your other, production server. The general recommendation is to have one .env file per host.
If you still need to however, you can use the following dotenv configuration :
require('dotenv').config({ path: '/custom/path/to/.env' })
Remember to not store any secret in your .env file in your react app.

Related

.env variables not available in jest testing environment

When I run my code normally I can access my .env file with const newVar = process.env.MY_DOTENV_VARIABLE, but when I run jest everything becomes undefined. Is this normal for jest? If so, what is the best practice for storing variables?
Is it simply to create a set up file, eg:
// jest.config.ts
setupFiles: [
"<rootDir>/.jest/setEnvVars.ts",
],
# .env
MY_DOTENV_VARIABLE=exampleString
I just needed to install dotenv. I think I got confused where process.env was working previously without the dotenv packaging. This was either due to me setting the env variables with scripts in my package.json file, eg "scripts":"NODE_ENV=test ..." and/or some packages were making changes. (I'm using various aws packages, and I've read that they can change environment variables)

How to use .env file while deploying my app?

I want to deploy my app using Heroku but I have kept my API keys in .env file which will be ignored by .gitignore file while pushing to Heroku and after deploying my app on Heroku, it is no longer able to read my API keys and app crashes? What to do in this case? How to use it correctly?
If your not storing your .env file in your git repository (which is absolutely the correct thing to do) then you need to manually configure the .env file once you deploy it.
In the instance of Heroku you can set Config Vars:
Configuration and Config Vars
If you do it that way I believe you have to access the vars in a different manor to env values but it has a local mode so that shouldn't be a problem.
You have to specify all the API keys in your START script in "package.json". Like below
"start": "MONGO_USER=abcis app.js"

Toggle between multiple .env files like .env.development with node.js

I want to use separate .env files for each mode (development, production, etc...). When working on my vue.js projects, I can use files like .env.development or .env.production to get different values for the same env key. (example: in .env.development: FOO=BAR and in .env.production: FOO=BAZ, in development mode process.env.FOO would be BAR, in production i'd be BAZ).
I'm working on an Express server and want to use these same kinds of .env files to store the port, db uri, user, pwd...
I know I can edit the scripts in package.json like this:
"scripts": {
"start": "NODE_ENV=development PORT=80 node ./bin/www",
"start-prod": "NODE_ENV=production PORT=81 node ./bin/www"
}
but this gets messy when using multiple variables.
I've tried using dotenv but it seems like you can only use the .env file. Not .env.development and .env.production.
Can I use the dotenv package or do I need another one? Or could I do this without any package at all?
You can specify which .env file path to use via the path option with something like this:
require('dotenv').config({ path: `.env.${process.env.NODE_ENV}` })
The above two answers are both slightly off. let me explain. Answer from KyleMit below is missing ./ to indicate current directory.
the ./ indicates current directory in Node.js. The Second . prior to env indicates a hidden/private file. Thats why in KyleMits answer if the env file was not in the root of the PC it would never find it. The simplest way to do it in my opinion is to add a ./
this says "hey computer look in my current directory for this file".
//look in my current directory for this hidden file.
// List hidden files in dir: ls -a
require('dotenv').config({ path: `./.env.${process.env.NODE_ENV}` })
//I reccomend doing a console.log as well to make sure the names match*
console.log(`./.env.${process.env.NODE_ENV}`)
I'm using the custom-env npm package to handle multiple .env files. Just put this at the top of your code:
require('custom-env').env();
and it will load environment variables from the file .env.X, where X is the value of you NODE_ENV environment variable. For example: .env.test or .env.production.
Here is a nice tutorial on how to use the package.
From answers from above:
This is the final result that worked for me.
.env.dev file in src dir.
import path from 'path';
dotenv.config({ path: path.join(__dirname, `./.env.${process.env.NODE_ENV}`)});
For Typescript:
import dotenv from 'dotenv'
dotenv.config({ path: `.env.${process.env.NODE_ENV}` })
Install the dotenv package:
npm install dotenv
We need to get the .env file name based on NODE_ENV, it might be undefined, set default to development:
const envFileName = `.env.${process.env.NODE_ENV || "development"}`
Import the dotenv package and use it:
dotenv.config({ path: envFileName });
The official doc of dotenv does not recommend having multiple .env files.
"Should I have multiple .env files?
No. We strongly recommend against having a "main" .env file and an
"environment" .env file like .env.test. Your config should vary
between deploys, and you should not be sharing values between
environments."

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!

Resources