Node.js Application Configuration Files

What is the best practice to make configuration file for your Node.js application? Writing property file parser or passing parameters at command line is cumbersome.

Eval

One easy way to separate configuration and application code is by using eval statement. Define your configuration as simple Javascript associative array and load and evaluage it on app startup.

Example configuration file myconfig.js

settings = {
    a: 10,
    // this is used for something
    SOME_FILE: "/tmp/something"
}

Then at start of your application

var fs = require('fs');
eval(fs.readFileSync('myconfig.js', encoding="ascii"));

Now settings object can be used as your program settings. e.g.

var mydata = fs.readFileSync(settings.SOME_FILE);
for( i = 0 ; i < settings.a ; i++) {
   // do something
}

Require

Another alternative to load configuration, as stated in comments, is to define configuration as module file and require it.

//-- configuration.js
module.exports = {
  a: 10,
  SOME_FILE: '/tmp/foo'
}

In application code then require file

var settings = require('./configuration');

This prevents other global variable creeping in global scope, but it’s hackier to do dynamic configuration reloading. If you detect that file has changed, and would want to reload it at runtime you must delete entry from require cache and re-require the file. Another minor complication is that require uses its own search path (that you can override with NODE_PATH env. variable) so it’s more work to define dynamic location for configuration file in your app. (e.g. set it from command line).

// to reload file with require
var path = require('path');
var filename = path.resolve('./configuration.js');
delete require.cache[filename];
var tools = require('./configuration');

Plain javascript as configure file has benefit (and downside) that it’s possible to run any javascript in the settings. For example.

settings = {
    started: new Date(),
    nonce: ~~(1E6 * Math.random()),
    a: 10,
    SOME_FILE: "/tmp/something"
}

Both of these methods are mostly matter of taste. Eval is bit riskier as it allows leaking variables to global namespace but you’ll never have anything “stupid” in the configuration files anyway. Right?

JSON file

I’m not fan of using JSON as configuration format as it’s cumbersome to write and most editors are not able to show syntax errors in it. JSON also does not support comments that can be a big problem in more complicated configuration files.
Example configuration file myconfig.json

{
   "a":10,
   "SOME_FILE":"/tmp/something"
}

Then at start of your application read json file and parse it to object.

var fs = require('fs');
var settings = JSON.parse(fs.readFileSync('myconfig.json', encoding="ascii"));

And then use settings as usual

var mydata = fs.readFileSync(settings.SOME_FILE);
for( i = 0 ; i < settings.a ; i++) {
   // do something
}

Merging configuration files

One way to simplify significantly configuration management is to do hierarchical configuration. For example have single base configuration file and then define overrides for developer, testing and production use.

For this we need merge function.

// merges o2 properties to o1
var merge = exports.merge = function(o1, o2) {
    for (var prop in o2) {
         var val = o2[prop];
         if (o1.hasOwnProperty(prop)) {
             if (typeof val == 'object') {
                 if (val && val.constructor != Array) { // not array
                     val = merge(o1[prop], val);
                 }
             }
         }
         o1[prop] = val; // copy and override
    }
    return o1;
}

You can use merge to combine configurations. For example, lets have these two configuration objects.

// base configuration from baseconf.js
var baseconfig = {
    a: "someval",
    env: {
        name "base",
        code: 1
    }
}

// test config from localconf.js
var localconfig = {
    env: { 
        name "test"
        db: 'localhost'
    },
    test: true
}

Now it’s possible to merge these easily

var settings = merge( baseconfig, localconfig );

console.log( settings. a ); // prints 'someval'
console.log( settings.env.name ); // prints 'test'
console.log( settings.env.code ); // prints '1'
console.log( settings.env.db ); // prints 'localhost'
console.log( settings.env.test ); // prints 'true'

9 Responses to Node.js Application Configuration Files

  1. Thanks, this really helped me!

  2. Pingback: CodeBudo » Blog Archive » Application Configuration for Node.js

  3. There is a small typo in your post, the code to read a file and eval should be:

    eval(fs.readFileSync(‘myconfig.js’, encoding=”ascii”));

  4. Nick says:

    Why not just store your settings as a module? Then you can utilize require() to keep a single reference to it.

    appSettings.js:
    exports.settings =
    { settingName: ‘this is cool!’
    , settingName2: true
    }

    Usage:
    var settings = require(‘./appSettings.js’).settings;

    console.log(settings.settingName);

    • tikonen says:

      require() is good way to load settings, however I wanted to keep settings strictly as separate from the modules. Matter of taste methinks.

  5. Vesa Laakso says:

    Why on earth would you use eval? eval is evil. Use JSON instead, or with comments it’s cjson: https://github.com/kof/node-cjson

  6. felipe.polowood says:

    Nice article, thanks for sharing… one small addition… for your json file, you don’t have to use filesystem to load it.

    var settings = require(‘myconfig.json’);

    loads the json file as a json object in the settings variable (pretty much the same as your code did, but in one line).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: