(Node.js) config done right
The Problem 😕
Let’s look at config NPM package.
config suggests to break configuration in separate files based on environment: config/default.json, config/production.json, etc. Based on NODE_ENV value production configuration may overwrite default.
Configuration usually have data for resources you need to initialize separately (database, cache). You will do so in application startup script.
config seems like a good example of separation of concerns principle.
- Environment specific files
- Resources initialization is separate from config itself
However, it is a bad way to separate concerns.
The value of separation of concerns is simplifying development and maintenance of computer programs. When concerns are well-separated, individual sections can be reused, as well as developed and updated independently
— wikipedia (link)
🦄 Imagine that you have a few micro-services that use MongoDB. As you product grows you decide to switch from standalone server to Replica Set. Now you need to change data in every single environment specific config JSON and MongoDB initialization code in every single micro-service index.js that uses it.
Or 🦄 imagine that you need to check some data about MongoDB configuration, for example database port for production. You open config/production.json, find entry for MongoDB and see no entry for database port. What does it mean? Maybe it’s defined in config/default.json or maybe default value is used. You never know unless you check multiple config files.
As you can see separation by environments makes little sense. Instead, it’s better to separate by resources: /config/mongodb.json, /config/redis.json. Or even single /config.json:
Much easier to maintain, right? Even better if we put resource initialization code right into resource config:
If your init logic become complex, extract it to a separate file:
Even the logic is not in the same file, it’s still within the same resource 👍
If you like this approach to organise config and want to use it in your project, you can use no-config NPM module. It uses exactly the same format. Enjoy!
UPDATE: some readers haven’t checked no-config GitHub page and misunderstood its usage.
For example, some assumed that I suggest to drop NODE_ENV and access config data like config.mongo.production.host. Wrong.
👈 For readers convenience, I’ve included no-config Quick Start on the left side (packed in one .js file).
Note that NODE_ENV is used to run the file. After config is loaded, Redis configuration data can be accessed directly without environment key word. Also, conf.redis.instance was initialized from init().
Bonus: Separation of concerns RANT
I’ve made no-config as an internal code for personal project, but this video from Mattias Petter Johansson inspired me to publish it and write why it is important. Thanks Mattias.