Skip to content

Instantly share code, notes, and snippets.

@timoxley
Created March 18, 2012 12:34
Show Gist options
  • Save timoxley/2071419 to your computer and use it in GitHub Desktop.
Save timoxley/2071419 to your computer and use it in GitHub Desktop.
environment-aware nconf config with better defaults handling

nconf becomes environment aware.

In the following example we have settings for test, development and production environments. defaults is used where a value for that particular key is not supplied for the current environment.

{
  "test": {
    "url": "localhost"
  },
  "staging": {
    "url": "staging.com"
  },
  "production": {
    "url": "production.com",
    "port": 80
  },
  "defaults": {
    "port": 3000
  }
}

Usage:

// ./config/index.js
'use strict'
var auto_nconf = require('./auto_nconf')

// create main settings configuration
var settings = exports.settings = auto_nconf.createConfiguration('settings', __dirname)
// create additional configuration for 'types'
var types = auto_nconf.createConfiguration('types', __dirname)
// ./lib/somefile.js
'use strict'
var config = require('../config') // load our config
var settings = config.settings // access settings
db.connect(settings.db.hostname) // for example

Environment

Environment can be set explicitly by setting NODE_ENV environment variable, or auto-detected. Auto detection tries to determine if you are running inside a test suite, or running the app manually. If in test suite, use test settings, if manually testing app, use development settings.

Where this is useful is for cases where you want to have smaller, faster data in test mode than development mode. E.g. limit the number of items per page to a small number in test mode to improve test suite speed, while when testing manually, use more human-friendly numbers.

Default Settings File

Recommended usage is to supply a default settings.defaults.json in your config folder, and override any settings specific to the current system in your top-level folder with a settings.json. The settings.json probably wouldn't be committed to version control and would contain things like local db passwords and personal cloud storage keys.

This file can contain both defaults and per-environment settings.

'use strict'
var nconf = require('nconf')
var pkginfo = require('pkginfo')(module, 'main')
var _ = require('underscore')
var path = require('path')
function isRunningAsTestSuite() {
// if 'main' isn't the application itself, we're usually inside a test runner
return require.main && (require.main.filename != path.resolve(exports.main))
}
function detectEnvironment() {
// if supplied with an environment, simply use that
if (process.env.NODE_ENV) return process.env.NODE_ENV
// Otherwise, try to infer environment from invocation method
if (isRunningAsTestSuite()) {
return 'test'
} else {
return 'development'
}
}
function getLoadPaths(type, configDir) {
var paths = Object.create(null)
// 'eg config/settings.defaults.json'
paths.defaults = path.join(configDir, type + '.defaults.json')
// 'eg' ./settings.json
paths.overrides = path.join(process.cwd(), type + '.json')
var loadPaths = [paths.defaults]
if (path.existsSync(paths.overrides)) {
loadPaths.push(paths.overrides)
}
return loadPaths
}
function getConfiguration(type, currentEnvironment) {
var config = nconf.stores[type]
var defaults = config.get('defaults')
var environmentOverrides = config.get(currentEnvironment)
_.extend(defaults, environmentOverrides)
return defaults
}
function createConfiguration(type, configDir) {
nconf.add(type, {
type: 'memory',
loadFrom: getLoadPaths(type, configDir)
})
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = detectEnvironment()
}
return getConfiguration(type, process.env.NODE_ENV)
}
exports.createConfiguration = createConfiguration
exports.detectEnvironment = detectEnvironment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment