I just started learning JavaScript / node.js (a gentle introduction to back-end webdev), and thus I am completely green in the subject.
A few days ago I was reading a tutorial from which I learned to keep my confidential data (like passwords) in a config.json file.
Today I have discovered (by a chance) .env file, and the more I learn about it, it seems, the more people are using it to actually store passwords.
So when should I use .env and when should I use config.json?
The Question
When should .env be used over config.json and for what?
The answer
This is a rather difficult answer. On the one hand, you should only really ever use either of these tools while in development. This means that when in a production or prod-like environment, you would add these variables directly to the environment:
NODE_ENV=development node ./sample.js --mongodb:host "dharma.mongohq.com" --mongodb:port 10065
There is no real clear winner over the other per se as they are both helpful in different ways. You can have nested data with config.json, but on the other hand, you can also have a cleaner data structure with .env
Some thing also to note is that you never want to commit these files to source control (git, svc etc).
On the other hand, these tools make it very easy for beginners to get started quickly without having to worry about how to set the environment variables and the differences between a windows environment and a linux one.
All in all, I'd say its really up to the developer.
.env files are generally used to store information related to the particular deployment environment, while config.json files might be used to store data particular to the application as a whole.
either approach works, and whether or not your config files are stored in your repository is more a function of whether the data needs to be confidential.
This largely comes down to personal preference and the conventions of the frameworks you're using. They're just different formats for storing the same kind of information.
Some example config file formats:
.env
*.yml (YAML files)
*.ini (normally Windows-only)
*.json
At the end of the day, they all accomplish the same purpose: providing your application with environment-specific information (credentials, file paths, connection strings, etc.). Choose the format which best fits your choice of framework.
I think it's really up to you, the important thing to remember is why you're using this approach. The idea is to save your sensitive data in a file that doesn't get pushed to source control or any other place other than your local environment - this keeps the data safer. Then when you're ready to deploy to a remote server somewhere, you need to manually insert those values into that environment.
I generally use .env because the syntax for getting data from a .env file is supported in many remote environments - like heroku. When I deploy an app to heroku, I can go into the settings of the app and put in the environment variables using the heroku dashboard UI - I don't have to figure out how to get a json file manually created, etc... (maybe there are other workarounds). After the variables are in place, I just use process.env.variableName to access the data.
Statistically comparing the two NPM packages (along with other similar solutions) might be the best way to decide for yourself.
At the time of this writing, dotenv is a much smaller package with greater support (actual contributors aside, only deduced by the number of remaining issues and immense popularity). It's also newer by 2.5 years and, if fanfare is important to you, has twice as many stars.
If you are targeting deployment of your application in Docker, then .env is 100% the way to go. The ability to use nested data in config.json is great, but you'll be looking at some PITA when you need to migrate that data to a .env to make deployment with Docker work. docker build and docker-compose both are designed to use .env natively, so if you start with that then it will facilitate a smooth path to "Dockerizing" your application.
I am currently porting an application to run in Docker which was written with no such forethought, and it is quite painful... lots of refactoring, and only for the nested stuff. The basic key:value properties are easy to migrate to a .env:
~$ cat config.json
{
"PROTOCOL": "https",
"HOST": "example.com",
"PORT": 443
}
...
~$ cat .env
PROTOCOL="https"
HOST="example.com"
PORT=443
I prefer json because typescript can infer type from it, this is not possible with env file
I'm using the following Vue SPA boilerplate, which is based on webpack.
When the app is running in the dev server or as a deployed version, I'm able to make use of process.env.NODE_ENV to determine whether if it's a development or production build. So far so good.
What I'm after is a way to pass command line arguments that can be parsed in the same fashion, i.e. npm run dev --foo=1 and fetch it using something like process.argv.slice(2).foo.
I've tried accessing things like accessing the command line arguments using process.argv inside the config files and decorating the config files.
I have also tried passing arguments through "env" --env.foo and changing the node modules export to something like
module.exports = env => {
// make use of env
}
without success.
Am I missing something obvious?
The usual pattern for this type of thing is to maintain multiple complete configuration files and choose between them when they are loaded, even though it is arguably more concise not to.
I'll also add that while you may want a command-line flags for ergonomic reasons,
env="foo" npm run dev
and
npm run dev --env=foo
are both equally workable in most situations.
Is it ok to have more than one package.json in a project? I'm working in a .NET MVC solution and it has a package.json at the root level. I need to integrate Jasmine/Karma into the solution and this is my first time doing this type of integration. I found a sample project for Jasmine/Karma on the web and I was able to get this running locally. This project has it's own package.json.
It seems like it would be useful to maintain the package.json file for the sample Jasmine/Karma sample project separately from the package.json at the root level of the solution to provide more flexibility and to allow the same properties to be used differently based on context.
Would this be valid or generally considered an ok practice? Or do I need to figure out how to merge the contents of package.json from the sample project into the package.json at the root level of the .NET MVC solution?
In terms of keeping things simple, it is easier to only have to maintain a single package.json file, but there is nothing inherently wrong with multiple package.json files within a repo. Some companies do use mono-repos, for which it would make total sense to have multiple package.json files.
Multiple package.json files give you a lot of flexibility to run different/incompatible versions of dependencies. As a practical example, on one of the projects that I work on we have 2 package.json files, one for the main application code and then another one for our BDD tests. We use chimp for our BDD tests and had issues with running that on the latest node version, whereas we don't want to keep the rest of the app from upgrading just because of this. We also found that the single package.json file got very messy when it was combined at first.
I would say its typically bad practice to have more than one package.json. I would only expect to have to npm install once, and having to deal with two sets of dependency management could lead to issues down the line.
I've noticed that I have Angular 2 installed globally, and I don't know when I might have done that, or if that's the way it's supposed to be. It doesn't seem like that would be necessary if it's defined in every project.
It makes me wonder what side effects that have if I had different versions locally and globally. Which one takes priority? What's the best way to remove all of the Angular packages.
Globally installed NPM packages really only impact your command-line environment. Things like pm2 or sequelize insert bin/ stubs into the PATH to make your life easier.
In order to require something it needs to be present in package.json as well as properly installed.
I'm using Meteor with less package, and trying to make a variable different on each environment. For example:
// on Dev
#staticPath: '/'
// on Production
#staticPath: 'http://s.mydomain.com/'
Any idea?
Thanks.
It is a bit difficult to do this comparing the effort you have to put in to compared with what you get.
You can create a package in your project that is a 'dev mode' package and another thats a production mode package
meteor create --package debugmode
meteor create --package productionmode
In the packages directory you should have two packages, in the debugmode package you can edit the package.js file and add debugOnly: true into the Package.describe method.
You can also add api.use("debugmode", "less") to the Package.onUse(function(api) { section of it. This ensures that if productionmode has a variable, then debugmode will override it.
You'll also need an api.use("less") in the productionmode package since its dependent on less.
In both packages you will have to use api.add_files to add any less files that are production mode or debug mode. Keep in mind debug mode overrides production mode so the variable names need to match. If you declare a production mode variable it will have to be nullified by the debug mode package.
Lastly add the packages in with meteor add productionmode debugmode
I've never personally tried this, but a variation of it in some way (perhaps including all the less files) in the two packages should work.