Another Node.js Configuration Pattern

 •  Filed under nodejs

I'm becoming a fan of Yos Riady's blog. He's got this nice node.js configuration pattern, which introduced me to the glory of nconf. Unfortunately, that pattern doesn't quite have the flexibility I seek, and leaves more up to nconf's convoluted resolution system than I'd like. So here's mine, with the help of Ramda, my favorite utility belt.

const nconf = require('nconf')
const R = require('ramda')

const defaults =
  {
    'node_env': 'development',
    'mongo': {
      'host': 'mongo',
      'collection': 'mything'
    }
  }

const testDefaults = {
  'mongo': { 'db': 'mything-test' }
}

const localhostDefaults = {
  'mongo': { 'host': 'localhost' }
}

function Config() {

  nconf.argv().env({ lowerCase: true })  // get NODE_ENV as node_env

  const mergeAllDeepRight = R.reduce(R.mergeDeepRight, {})
  const computedDefaults = mergeAllDeepRight([
    defaults,
    this.env.isTest ? testDefaults : {},
    nconf.get('localhost_services') === '1' ? localhostDefaults : {}
  ])

  nconf.defaults(computedDefaults)
}

Config.prototype.get = function(key) {
  return nconf.get(key)
}

// for convenience, because `config.env.isTest` is real nice
const nodeEnv = process.env.NODE_ENV
Config.prototype.env = {
  'isProd':  nodeEnv === 'production',
  'isTest': nodeEnv === 'testing',
  'isDev': nodeEnv === 'development'
}

module.exports = new Config()

This makes the rules about how defaults are loaded very explicit and very flexible.