Giter Club home page Giter Club logo

nconf's Introduction

nconf

Version npmnpm DownloadsBuild StatusCoverageDependencies

Hierarchical node.js configuration with files, environment variables, command-line arguments, and atomic object merging.

Example

Using nconf is easy; it is designed to be a simple key-value store with support for both local and remote storage. Keys are namespaced and delimited by :. Let's dive right into sample usage:

  // sample.js
  var nconf = require('nconf');

  //
  // Setup nconf to use (in-order):
  //   1. Command-line arguments
  //   2. Environment variables
  //   3. A file located at 'path/to/config.json'
  //
  nconf.argv()
   .env()
   .file({ file: 'path/to/config.json' });

  //
  // Set a few variables on `nconf`.
  //
  nconf.set('database:host', '127.0.0.1');
  nconf.set('database:port', 5984);

  //
  // Get the entire database object from nconf. This will output
  // { host: '127.0.0.1', port: 5984 }
  //
  console.log('foo: ' + nconf.get('foo'));
  console.log('NODE_ENV: ' + nconf.get('NODE_ENV'));
  console.log('database: ' + nconf.get('database'));

  //
  // Save the configuration object to disk
  //
  nconf.save(function (err) {
    require('fs').readFile('path/to/your/config.json', function (err, data) {
      console.dir(JSON.parse(data.toString()))
    });
  });

If you run the below script:

  $ NODE_ENV=production node sample.js --foo bar

The output will be:

  foo: bar
  NODE_ENV: production
  database: { host: '127.0.0.1', port: 5984 }

Hierarchical configuration

Configuration management can get complicated very quickly for even trivial applications running in production. nconf addresses this problem by enabling you to setup a hierarchy for different sources of configuration with no defaults. The order in which you attach these configuration sources determines their priority in the hierarchy. Let's take a look at the options available to you

  1. nconf.argv(options) Loads process.argv using yargs. If options is supplied it is passed along to yargs.
  2. nconf.env(options) Loads process.env into the hierarchy.
  3. nconf.file(options) Loads the configuration data at options.file into the hierarchy.
  4. nconf.defaults(options) Loads the data in options.store into the hierarchy.
  5. nconf.overrides(options) Loads the data in options.store into the hierarchy.

A sane default for this could be:

  var nconf = require('nconf');

  //
  // 1. any overrides
  //
  nconf.overrides({
    'always': 'be this value'
  });

  //
  // 2. `process.env`
  // 3. `process.argv`
  //
  nconf.env().argv();

  //
  // 4. Values in `config.json`
  //
  nconf.file('/path/to/config.json');

  //
  // Or with a custom name
  // Note: A custom key must be supplied for hierarchy to work if multiple files are used.
  //
  nconf.file('custom', '/path/to/config.json');

  //
  // Or searching from a base directory.
  // Note: `name` is optional.
  //
  nconf.file(name, {
    file: 'config.json',
    dir: 'search/from/here',
    search: true
  });

  //
  // 5. Any default values
  //
  nconf.defaults({
    'if nothing else': 'use this value'
  });

API Documentation

The top-level of nconf is an instance of the nconf.Provider abstracts this all for you into a simple API.

nconf.add(name, options)

Adds a new store with the specified name and options. If options.type is not set, then name will be used instead:

  nconf.add('supplied', { type: 'literal', store: { 'some': 'config' } });
  nconf.add('user', { type: 'file', file: '/path/to/userconf.json' });
  nconf.add('global', { type: 'file', file: '/path/to/globalconf.json' });

nconf.any(names, callback)

Given a set of key names, gets the value of the first key found to be truthy. The key names can be given as separate arguments or as an array. If the last argument is a function, it will be called with the result; otherwise, the value is returned.

  //
  // Get one of 'NODEJS_PORT' and 'PORT' as a return value
  //
  var port = nconf.any('NODEJS_PORT', 'PORT');

  //
  // Get one of 'NODEJS_IP' and 'IPADDRESS' using a callback
  //
  nconf.any(['NODEJS_IP', 'IPADDRESS'], function(err, value) {
    console.log('Connect to IP address ' + value);
  });

nconf.use(name, options)

Similar to nconf.add, except that it can replace an existing store if new options are provided

  //
  // Load a file store onto nconf with the specified settings
  //
  nconf.use('file', { file: '/path/to/some/config-file.json' });

  //
  // Replace the file store with new settings
  //
  nconf.use('file', { file: 'path/to/a-new/config-file.json' });

nconf.remove(name)

Removes the store with the specified name. The configuration stored at that level will no longer be used for lookup(s).

  nconf.remove('file');

nconf.required(keys)

Declares a set of string keys to be mandatory, and throw an error if any are missing.

  nconf.defaults({
    keya: 'a',
  });

  nconf.required(['keya', 'keyb']);
  // Error: Missing required keys: keyb

You can also chain .required() calls when needed. for example when a configuration depends on another configuration store

config
  .argv()
  .env()
  .required([ 'STAGE']) //here you should have STAGE otherwise throw an error
  .file( 'stage', path.resolve( 'configs', 'stages', config.get( 'STAGE' ) + '.json' ) )
  .required([ 'OAUTH:redirectURL']) // here you should have OAUTH:redirectURL, otherwise throw an error
  .file( 'oauth', path.resolve( 'configs', 'oauth', config.get( 'OAUTH:MODE' ) + '.json' ) )
  .file( 'app', path.resolve( 'configs', 'app.json' ) )
  .required([ 'LOGS_MODE']) // here you should haveLOGS_MODE, otherwise throw an error
  .add( 'logs', {
    type: 'literal',
    store: require( path.resolve( 'configs', 'logs', config.get( 'LOGS_MODE' ) + '.js') )
  } )
  .defaults( defaults );

Storage Engines

Memory

A simple in-memory storage engine that stores a nested JSON representation of the configuration. To use this engine, just call .use() with the appropriate arguments. All calls to .get(), .set(), .clear(), .reset() methods are synchronous since we are only dealing with an in-memory object.

All built-in storage engines inherit from the Memory store.

Basic usage:

  nconf.use('memory');

Options

The options defined below apply to all storage engines that inherit from Memory.

accessSeparator: string (default: ':')

Defines the separator used to get or set data using the get() and set() methods. Even if this is changed, the default "colon" separator will be available unless explicitly disabled (see disableDefaultAccessSeparator).

inputSeparator: string (default: '__')

This option is used by the argv and env storage engines when loading values. Since most systems only allow dashes, underscores, and alphanumeric characters in environment variables and command line arguments, the inputSeparator provides a mechanism for loading hierarchical values from these sources.

disableDefaultAccessSeparator: {true|false} (default: false)

Disables the default access separator of ':', which is always available otherwise. This is mainly used to preserve legacy behavior. It can also be used to set keys that contain the default separator (e.g. { 'some:long:key' : 'some value' }).

Argv

Responsible for loading the values parsed from process.argv by yargs into the configuration hierarchy. See the yargs option docs for more on the option format.

Options

parseValues: {true|false} (default: false)

Attempt to parse well-known values (e.g. 'false', 'true', 'null', 'undefined', '3', '5.1' and JSON values) into their proper types. If a value cannot be parsed, it will remain a string.

transform: function(obj)

Pass each key/value pair to the specified function for transformation.

The input obj contains two properties passed in the following format:

{
  key: '<string>',
  value: '<string>'
}

The transformation function may alter both the key and the value.

The function may return either an object in the same format as the input or a value that evaluates to false. If the return value is falsey, the entry will be dropped from the store, otherwise it will replace the original key/value.

Note: If the return value doesn't adhere to the above rules, an exception will be thrown.

Examples

  //
  // Can optionally also be an object literal to pass to `yargs`.
  //
  nconf.argv({
    "x": {
      alias: 'example',
      describe: 'Example description for usage generation',
      demand: true,
      default: 'some-value',
      parseValues: true,
      transform: function(obj) {
        if (obj.key === 'foo') {
          obj.value = 'baz';
        }
        return obj;
      }
    }
  });

It's also possible to pass a configured yargs instance

  nconf.argv(require('yargs')
    .version('1.2.3')
    .usage('My usage definition')
    .strict()
    .options({
      "x": {
        alias: 'example',
        describe: 'Example description for usage generation',
        demand: true,
        default: 'some-value'
      }
    }));

Env

Responsible for loading the values parsed from process.env into the configuration hierarchy. By default, the env variables values are loaded into the configuration as strings.

Options

lowerCase: {true|false} (default: false)

Convert all input keys to lower case. Values are not modified.

If this option is enabled, all calls to nconf.get() must pass in a lowercase string (e.g. nconf.get('port'))

parseValues: {true|false} (default: false)

Attempt to parse well-known values (e.g. 'false', 'true', 'null', 'undefined', '3', '5.1' and JSON values) into their proper types. If a value cannot be parsed, it will remain a string.

transform: function(obj)

Pass each key/value pair to the specified function for transformation.

The input obj contains two properties passed in the following format:

{
  key: '<string>',
  value: '<string>'
}

The transformation function may alter both the key and the value.

The function may return either an object in the same format as the input or a value that evaluates to false. If the return value is falsey, the entry will be dropped from the store, otherwise it will replace the original key/value.

Note: If the return value doesn't adhere to the above rules, an exception will be thrown.

readOnly: {true|false} (default: true)

Allow values in the env store to be updated in the future. The default is to not allow items in the env store to be updated.

Examples

  //
  // Can optionally also be an Array of values to limit process.env to.
  //
  nconf.env(['only', 'load', 'these', 'values', 'from', 'process.env']);

  //
  // Can also specify an input separator for nested keys
  //
  nconf.env('__');
  // Get the value of the env variable 'database__host'
  var dbHost = nconf.get('database:host');

  //
  // Can also lowerCase keys.
  // Especially handy when dealing with environment variables which are usually
  // uppercased while argv are lowercased.
  //

  // Given an environment variable PORT=3001
  nconf.env();
  var port = nconf.get('port') // undefined

  nconf.env({ lowerCase: true });
  var port = nconf.get('port') // 3001

  //
  // Or use all options
  //
  nconf.env({
    inputSeparator: '__',
    match: /^whatever_matches_this_will_be_whitelisted/
    whitelist: ['database__host', 'only', 'load', 'these', 'values', 'if', 'whatever_doesnt_match_but_is_whitelisted_gets_loaded_too'],
    lowerCase: true,
    parseValues: true,
    transform: function(obj) {
      if (obj.key === 'foo') {
        obj.value = 'baz';
      }
      return obj;
    }
  });
  var dbHost = nconf.get('database:host');

Literal

Loads a given object literal into the configuration hierarchy. Both nconf.defaults() and nconf.overrides() use the Literal store.

  nconf.defaults({
    'some': 'default value'
  });

File

Based on the Memory store, but provides additional methods .save() and .load() which allow you to read your configuration to and from file. As with the Memory store, all method calls are synchronous with the exception of .save() and .load() which take callback functions.

It is important to note that setting keys in the File engine will not be persisted to disk until a call to .save() is made. Note a custom key must be supplied as the first parameter for hierarchy to work if multiple files are used.

  nconf.file('path/to/your/config.json');
  // add multiple files, hierarchically. notice the unique key for each file
  nconf.file('user', 'path/to/your/user.json');
  nconf.file('global', 'path/to/your/global.json');

The file store is also extensible for multiple file formats, defaulting to JSON. To use a custom format, simply pass a format object to the .use() method. This object must have .parse() and .stringify() methods just like the native JSON object.

If the file does not exist at the provided path, the store will simply be empty.

Encrypting file contents

As of [email protected] it is now possible to encrypt and decrypt file contents using the secure option:

nconf.file('secure-file', {
  file: 'path/to/secure-file.json',
  secure: {
    secret: 'super-secretzzz-keyzz',
    alg: 'aes-256-ctr'
  }
})

This will encrypt each key using crypto.createCipheriv, defaulting to aes-256-ctr. The encrypted file contents will look like this:

{
  "config-key-name": {
    "alg": "aes-256-ctr", // cipher used
    "value": "af07fbcf",   // encrypted contents
    "iv": "49e7803a2a5ef98c7a51a8902b76dd10" // initialization vector
  },
  "another-config-key": {
    "alg": "aes-256-ctr",   // cipher used
    "value": "e310f6d94f13", // encrypted contents
    "iv": "b654e01aed262f37d0acf200be193985" // initialization vector
  },
}

Redis

There is a separate Redis-based store available through nconf-redis. To install and use this store simply:

  $ npm install nconf
  $ npm install nconf-redis

Once installing both nconf and nconf-redis, you must require both modules to use the Redis store:

  var nconf = require('nconf');

  //
  // Requiring `nconf-redis` will extend the `nconf`
  // module.
  //
  require('nconf-redis');

  nconf.use('redis', { host: 'localhost', port: 6379, ttl: 60 * 60 * 1000 });

Installation

  npm install nconf --save

Run Tests

Tests are written in vows and give complete coverage of all APIs and storage engines.

  $ npm test

License: MIT

nconf's People

Contributors

adrieankhisbe avatar bmeck avatar chjj avatar christianmurphy avatar dependabot[bot] avatar ebickle avatar f1729 avatar indexzero avatar jcrugzz avatar jfhbrook avatar jfromaniello avatar joaoafrmartins avatar josephpage avatar jstewmon avatar ljharb avatar mansona avatar marak avatar mfloryan avatar mhamann avatar mhart avatar midknight41 avatar mmalecki avatar moberemk avatar nickheiner avatar pksunkara avatar renovate[bot] avatar samsonjs avatar schoonologyrrl avatar tellnes avatar tommystanton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nconf's Issues

REPL server.start fail

hookio = require('hook.io');
require('repl').start({})
new hookio.Hook

results in the following error:

$ node foo.js 
> 
TypeError: undefined is not a function
    at Object.stores.create (/Users/crabdude/github/node_modules/hook.io/node_modules/nconf/lib/nconf/stores.js:35:10)
    at Provider.use (/Users/crabdude/github/node_modules/hook.io/node_modules/nconf/lib/nconf/provider.js:45:25)
    at Object.<anonymous> (/Users/crabdude/github/node_modules/hook.io/node_modules/nconf/lib/nconf.js:17:7)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:362:17)
    at require (module.js:378:17)
    at Object.<anonymous> (/Users/crabdude/github/node_modules/hook.io/node_modules/nconf/lib/nconf/stores/memory.js:8:13)

And it looks like it may be due to this weirdness, though I haven't checked:

nconf.__defineGetter__(name, function () {
    return require('./nconf/stores/' + store)[name];
  });

throws "TypeError: Object.keys called on non-object" on json with x:y = null

two files needed to reproduce this bug under nconf 0.6.4 : conf.json and test.coffee

cat conf.json

{
  "x":
  {
    "y":null
  }
}

cat test.coffee

config = require 'nconf'
config.add 'conf_file', type: 'file', file: './conf.json'
xcolony = config.get "x:y"
shell> coffee test
TypeError: Object.keys called on non-object
    at Function.keys (native)
    at common.merge (/home/gord/dev/local/lib/node_modules/nconf/lib/nconf/common.js:96:12)
    at Array.forEach (native)
    at Object.common.merge (/home/gord/dev/local/lib/node_modules/nconf/lib/nconf/common.js:95:8)
    at Provider._execute (/home/gord/dev/local/lib/node_modules/nconf/lib/nconf/provider.js:550:23)
    at Provider.get (/home/gord/dev/local/lib/node_modules/nconf/lib/nconf/provider.js:216:17)
    at Object.<anonymous> (/home/gord/DEV/nconf_check/test.coffee:11:19)
    at Object.<anonymous> (/home/gord/DEV/nconf_check/test.coffee:13:4)
    at Module._compile (module.js:449:26)
    at Object.exports.run (/home/gord/dev/local/lib/node_modules/coffee-script/lib/coffee-script/coffee-script.js:79:25)

My reasons for expecting nconf to handle null json keys are :

  • null keys are valid json [ eg. admitted by python -mjson.tool ]
  • null keys are useful in json config files because they keep placeholders, to suggest options for sysadmins/devs
  • I think earlier versions of nconf handled this gracefully

by the way.. we love nconf, it is truly awesome!!

using several stores / overrides - merges not as expected

Hi,
I'm trying to set up store as such:

conf.add 'user',   { type: 'file', file: 'config/config.local.json' }
conf.add 'global', { type: 'file', file: 'config/config.json' }

I then expect the user values to override the global values such that:

# user
{ port:4000}

# global
{ port:80}

but in every case i'm getting port:80 being resloved.
if i reverse the order like so:

conf.add 'global', { type: 'file', file: 'config/config.json' }
conf.add 'user',   { type: 'file', file: 'config/config.local.json' }

then i get undefined values, because global declares more values than in user.

# global
{ port:80, db:"host"}

# user
{ port:4000}

db is undefined -- seems to be overriden in user - but i'm not specifying it there in any case and expecting it to be merged from global.

anything i'm doing wrong here?

Thanks!

ERR wrong number of arguments for 'set' command

Could you please have a look what's wrong with redis storage engine?
Just run the script below to reproduce the issue.

Test script:

var nconf = require('nconf');
nconf.use('redis');
nconf.set('database:host', '127.0.0.1');
nconf.set('database:port', 5984);

Error log:

node_redis: no callback to send error: Error: ERR wrong number of arguments for 'set' command
node_redis: no callback to send error: Error: ERR wrong number of arguments for 'set' command

node.js:116
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
Error: Error: ERR wrong number of arguments for 'set' command
    at HiredisReplyParser. (/usr/local/lib/node/.npm/redis/0.5.9/package/index.js:84:27)
    at HiredisReplyParser.emit (events.js:42:17)
    at HiredisReplyParser.execute (/usr/local/lib/node/.npm/redis/0.5.9/package/lib/parser/hiredis.js:33:22)
    at RedisClient.on_data (/usr/local/lib/node/.npm/redis/0.5.9/package/index.js:328:27)
    at Socket. (/usr/local/lib/node/.npm/redis/0.5.9/package/index.js:99:14)
    at Socket.emit (events.js:42:17)
    at Socket._onReadable (net.js:649:14)
    at IOWatcher.onReadable [as callback] (net.js:156:10)

Additional info: after this error redis contains the following data:

$ redis-cli 
redis> keys *
1) "nconf:database:keys"
2) "nconf:keys"

Add Store for ENV variables

It would be nice for nconf to be able to interact better with a systems ENV variables.

Adding a store for ENV variables seems like the best choice.

nconf.defaults: "Object has no method 'defaults" (Example from readme.)

This example from the readme, doesn't seem to work, gives the following errors:

TypeError: Property 'overrides' of object [object Object] is not a function
TypeError: Property 'env' of object [object Object] is not a function
TypeError: Object [object Object] has no method 'file'
TypeError: Object [object Object] has no method 'defaults'

Am I missing something?

var nconf=require('nconf');

  //
  // 1. any overrides
  //
  nconf.overrides({
    'always':'be this value'
  });

  //
  // 2. `process.env`
  // 3. `process.argv`
  //
  nconf.env().argv();

  //
  // 4. Values in `config.json` 
  //
  nconf.file({file:'config.json'});

  //
  // 5. Any default values
  //
  nconf.defaults({
    'if nothing else':'use this value'
  });

nconf.file - how to specify namespace

Hi - it's not clear to me from the docs how to add a custom namespace when loading a file, I would expect:

// Or with a custom name
//
nconf.file('custom', '/path/to/config.json');

Assuming config.json to be something like:
{ key: 'foo', secret: 'bar' }

To be accessed like:
nconf.get('custom:key')
nconf.get('custom:secret')

But both those return undefined, instead you access them like:
nconf.get('key');
nconf.get('secret');

I want to namespace my configs so I can load multiple configs into the same nconf object. I don't want to have to namespace in my config json e.g.
{ s3-ket: 'foo', s3-secret: 'bar' }

So how to set a namespace when loading from a file?

Thanks

Store all

How to save values of all loaded keys?
Or how to get the values ​​of all keys (to save latter)?

  • I need to locally store the values ​​loaded from all sources for next time start

wish: option to lock() the configuration, so set() commands no longer work.

set() could be useful during a configuration phase, but once the app has started, for some use cases it would be a feature if the configuration could be "locked"-- that is: read-only, immutable.

Having a 'set' method available and usable gives the impression that it could be a good idea to change a configuration value deep within the application. This could cause an 'action at a distance' bug if code elsewhere in the application continues to expect that the value from the configuration file value is a constant.

Explicitly disabling the set() method would provide an immediate to a developer that using set() after configuration is done is not the way to do things.

nconf store memory has no loadSync() method

When I try this:

var nconf = require('nconf');

nconf.use('memory');
nconf.load();

I get this error

Error: nconf store memory has no loadSync() method
at loadStoreSync (./lib/nconf/provider.js:300:13)
at Array.map (native)
at loadBatch (./lib/nconf/provider.js:318:35)
at [object Object].load (./lib/nconf/provider.js:362:7)
at repl:1:7
at REPLServer.eval (repl.js:80:21)
at repl.js:190:20
at REPLServer.eval (repl.js:87:5)
at Interface. (repl.js:182:12)
at Interface.emit (events.js:67:17)

nconf.overrides won't merge as expected

Calling nconf.overrides the second time will replace every options set the first time.

nconf.overrides({
  modules1: {prop1: 'abc', prop2: 'def'}
});

// The following will replace every object in nconf.overrides specified before
nconf.overrides({
  moduleA: {newProp: 'foo'}
});

Am I doing it right? Is it the intended behavior of nconf.overrides?

Strict Mode

Please upgrade your version of async; running an app using nconf in strict mode results in the following error:

../node_modules/nconf/node_modules/async/lib/async.js:8
previous_async = root.async;
^
TypeError: Cannot read property 'async' of undefined

defaults behave like overrides if specified before other stores

Defaults behave like overrides if specified before other stores.

var nconf = require('nconf');

nconf.defaults({
  'ATTACK_ROLE': 'ninjas'
});

process.env['ATTACK_ROLE'] = 'pirates';
var whitelist = ['ATTACK_ROLE'];

nconf.env({
  whitelist: whitelist
});

console.log(nconf.get('ATTACK_ROLE')); //ninjas

In this case, even though I have an environment variable with the value 'pirates', I will always get 'ninjas'. If the call to defaults() is placed after env(), I will get 'pirates'.

I expect a default to be provided IF no other store has a value for a specified key, regardless of the order in which I declare stores.

Error on load() when config file doesn't exist

Just getting started with this module, cool stuff. It would be nice if load() would return something in err if the config file wasn't found. I can check for existence before I call load(), but this is redundant. Or if I'm missing something being a noob, please inform. My prototype is trying to load config, if it doesn't exist (initial startup, for example) create a default.

Provide the way to override attributes of settings

I'm trying to provide several configuration files which are overriding each other

config-default.json's settings are overriden by config-{DEV_ENV}.json and these by config-local.json

I'm using this:

conf.add('local-file', {'type': 'file', file: path.join(__dirname, './config-local.json')});
var current_env = process.env['DEV_ENV'] || 'development';
conf.add('env-file', {'type': 'file', file: path.join(__dirname, './config-' + current_env + '.json')});
conf.add('default-file', {'type': 'file', file: path.join(__dirname, './config-default.json')});

It's working well, however I'm unable to override parts of the object:
if config-default.json has a setting settingA defined in such way:

{
    "settingA": {
        "attributeA": "valueA",
        "attributeB": "valueB"
    }
}

it can be accessed by conf.get('settingA:attributeA'). I wish to override just this value in any other file. This is not working for obvious reasons (overrides entire setting):

{
    "settingA": {
        "attributeA": "localValueA"
    } 
}

But there is a syntax which isn't used and could work well:

{
    "settingA:attributeA": "localValueA"
}

Please tell me it's sane and if I'm using your lib in the right way.

win32 support?

Hi, once again ...

it possible to support win32 ??

npm install -g nconf

previous command fails =(

out:

npm ERR! cb() never called!
npm ERR!
npm not ok

Note: im running npm ok ... it works with various others packages ...

thks !

Incorrect module name in the redis.js file.

Hi,

Please correct module name in the lib/nconf/stores/redis.js line 5:

Memory = require('./Memory').Memory;

It must be:

Memory = require('./memory').Memory;

At the moment there is the following error:

$ node
> var nconf = require('nconf');
Error: Cannot find module './Memory'
    at Function._resolveFilename (module.js:320:11)
    at Function._load (module.js:266:25)
    at require (module.js:348:19)
    at Object. (/usr/local/lib/node/.npm/nconf/0.1.1/package/lib/nconf/stores/redis.js:11:14)
    at Module._compile (module.js:404:26)
    at Object..js (module.js:410:10)
    at Module.load (module.js:336:31)
    at Function._load (module.js:297:12)
    at require (module.js:348:19)
    at Object. (/usr/local/lib/node/.npm/nconf/0.1.1/package/lib/nconf/stores.js:16:17)
>

Thanks,
Alexey Ozerov.

Bug in optimist 0.3.x version...

Set cli varable like this:

node test.js --myobject.prop=www.google.com

dump optimist.argv show:

{ _: [],
myobject: { prop: -2147483648},
'$0': 'node ./index.js' }

Update to optimist 0.6.x remove this problem

api to call optimist.usage()

I would love to invoke usage() if the user specifies --help, for example. Is there any way to do that now? If not, can it be added please?

nconf multi instance?

Hi,

can i have multiple instances of nconf?

Something like:

var store1 = require('nconf').file({ file: __dirname+'/store1.json'});
var store2 = require('nconf').file({ file: __dirname+'/store2.json'});

store1.set('hello','store1');
store1.save();

store2.set('hello','store2');
store2.save();

This will only save "store2.json" file.

My goal is to read and save in multiple and independent files.
Any suggestion?

Thanks

Allow for multiple defaults

It would be really slick if we could something like the following:

nconf
.file('config', '/path/to/config')
.defaults({store: {user: {firstName: 'John', lastName: 'Doe'}}})
.defaults({store: {path: nconf.get('user:firstName') + ' ' nconf.get('user:lastName')}});

Otherwise, it gets messy when you have default values that depend on other default values.

Asynchronous not getting executed after checking synchronous

I am using file store to save some config and I called save() without any callback given. nconf then checked for any synchronous execution and threw error when not found.

I think, it should continue to check async execution and then use it with a dummy callback.

Regression: Uncaught exception when getting nested keys

When you set something to a string value and then attempt to get a child of that string value an unhandled Error is thrown.

This is a direct caused by incorrect use of the in keyword in #49

e.g.

  var nconf = require('nconf');
  nconf.set('foo:bar', 'SOME_STRING_VAUE');

  console.log(
    nconf.get('foo:bar:doesnt:exist') // should be undefined but throws
  );

Output final config state

Hello,
how can I output/dump the current state of my config? Assuming I have basic JSON, and then I do nconf.overrides, import .env(), .argv(), etc -- how can I see the final state of affairs (for all the initial variables)? Thanks!

nconf.file merges don't work correctly

2 problems:

  1. nconf.file defaults operate in the wrong order. You can see in this list below that the chain of overriding goes from top to bottom; the things listed higher up override the ones lower down. The nconf.file one operates in the reverse order, however. I had to swap those two lines to get this to work correctly in my app.
  2. If the first file listed is missing, it will delete all config, causing the defaults to be what gets selected. This is bad. Instead it should just not change any config.
nconf
  .argv()
  .env()
  .file({file: "#{process.env.HOME}/.groovebasinrc"})
  .file({file: "/etc/groovebasinrc"})
  .defaults
    log_level: 3
    http:
      port: 80
    mpd:
      host: 'localhost'
      port: 6600
      conf: "/etc/mpd.conf"

Configuration Change Events?

I guess that this is something of a feature request, or maybe just a thought on whether or not such an idea is valid and useful.

I guess what I want is to be notified if some piece of the configuration that I am using has changed for some reason. For example, if I change the value stored in a file, and these values ultimately made there way to being exposed as values in my configuration (that is to say, they have not been overridden by some other values, perhaps given at the command line or something) I would like the rest of my server to be notified so that it can smoothly transition to the new config.

For example, suppose that the port I am listening to for a web service is configured by a value in a config file. I would like to be able to change the config file, and have my service automatically respond to the change.

Perhaps what I a want is an event that I can listen to if some value in the configuration changes, and a new type of store that watches the source data for changes (eg file system watch or a zookeeper node watch).

argv-store should convert the strings "true" and "false" to booleans

Example

node app.js --myBool true results in nconf.get('myBool') // 'true'

I think converting boolean-string to real booleans would be nice, because that's what you are expecting - i think the same applies for the env-store.

I will attach a pull request if you agree on my proposal.

save error, but saves ...

Hi,

Im using nconf for a while ... and today making some refactors in my jakefile i found error when nconf save data (file mode), take a look :

var 
  nconf = require('nconf').use('file', { file: 'build.json' });
  version = nconf.get('version'),
  debug = nconf.get('debug'),
  development = nconf.get('development');
//...
nconf.set('build', new Date().getTime());  
//...
nconf.save(function (err) {
  if (err) {
    console.error(err.message); // nconf store system has no save() method ?!?!?
    return;
  }
});

the save method throws an exception "nconf store system has no save() method" but updates the use file ...

im doing someting wrong or its an issue ?? why exception says ... "store system" ... ??

thks guys !

Hierarchical argv overrides clobber entire objects

Here's a simple test case to illustrate what I mean.

test.json:

{
  "database": {
    "host": "localhost",
    "port": 3000
  }
}

test.js:

nconf = require('nconf')

nconf.argv().file({file: 'test.json'})

console.log(nconf.get('database'))

Then run using:

$ node test
{ host: 'localhost', port: 3000 }
$ node test --database:port 8080
{ port: 8080 }

As you can see, the entire database config object is getting clobbered when just one property is overridden. I would have expected just the single property to change/merge.

Is there another way to achieve this?

Descriptions provided to optimist.usage(...) are suppressed

nconf does not implement .usage(...) method.
I tried the following, but could not get nconf to display the usage message, or understand what I need to do to make it work.

The test code: test.js

var nconf = require('nconf');

require('optimist')
   .usage("This is explanation of usage");

nconf.argv(
  { x: 
    { demand: true
    , describe: "this is an x"
    , aliax : "xxs"
    }
  , y: 
    { demand: true
    , describe: "this is a y"
    , aliax : "yxs"
    }
  }
)

console.log( "x : %s, y: %s", nconf.get("x") , nconf.get("y") );

run as : node test.js

Expected:

This is explanation of usage

Options:
  -x, --xxs  this is an x  [required]
  -y, --yxs  this is a y   [required]

Missing required arguments: x, y

Found:

Options:
  -x  this is an x  [required]
  -y  this is a y   [required]

Missing required arguments: x, y

Mind also that the aliases are not displayed on the description

CLI: why is config changing after app.init()?

I have encountered a strange behaviour of the 'nconf' module, which happens only when used in a flatiron CLI app.

Basically, the config changes for whatever reason, after app.init().

Is this a bug or expected (if so, why?)


just the code, without setup:

// we run this with `node file.js --foo=bar`
console.log('foo: ' + app.config.get('foo'));
// now, `foo` is equal to config from argv

// the `init` changes the `app.config` ???
app.init();

console.log('foo: ' + app.config.get('foo'));
// now, `foo` is equal to config from `file` :/

I made tests with just using nconf, using it with flatiron, and using it as a CLI; it's all in one gist.

Object.keys called on non-object in common.js line 95 when trying to save settings to file

I get this error when I try to save my settings with nconf.

Actual code sample:

nconf.argv()
    .env()
    .file({ file: '../../settings.json' });

nconf.set('database:url', 'tcp://node:[email protected]/node');
nconf.set('server:port', 3000);

nconf.save();

Here’s my stack trace:

{
  "process": {
    "pid": 21552,
    "uid": 502,
    "gid": 502,
    "cwd": "/Users/mikl/Work/Node/knigu",
    "execPath": "/usr/local/Cellar/node/0.6.6/bin/node",
    "version": "v0.6.6",
    "argv": [
      "node",
      "/Users/mikl/Work/Node/knigu/bin/knigu",
      "generate_chapter_pointers"
    ],
    "memoryUsage": {
      "rss": 27222016,
      "heapTotal": 16700608,
      "heapUsed": 9358504
    }
  },
  "os": {
    "loadavg": [
      1.7314453125,
      1.5009765625,
      1.359375
    ],
    "uptime": 113788
  },
  "trace": [
    {
      "column": null,
      "file": null,
      "function": "Function.keys",
      "line": null,
      "method": "keys",
      "native": true
    },
    {
      "column": 12,
      "file": "/Users/mikl/Work/Node/knigu/node_modules/nconf/lib/nconf/common.js",
      "function": null,
      "line": 97,
      "method": null,
      "native": false
    },
    {
      "column": null,
      "file": null,
      "function": "Array.forEach",
      "line": null,
      "method": "forEach",
      "native": true
    },
    {
      "column": 8,
      "file": "/Users/mikl/Work/Node/knigu/node_modules/nconf/lib/nconf/common.js",
      "function": "Object.merge",
      "line": 95,
      "method": "merge",
      "native": false
    },
    {
      "column": 19,
      "file": "Object].save (/Users/mikl/Work/Node/knigu/node_modules/nconf/lib/nconf/provider.js",
      "function": "[object",
      "line": 415,
      "method": null,
      "native": false
    },
    {
      "column": 9,
      "file": "/Users/mikl/Work/Node/knigu/lib/commands/generate_chapter_pointers.js",
      "function": null,
      "line": 18,
      "method": null,
      "native": false
    },
    {
      "column": 19,
      "file": "/Users/mikl/Work/Node/knigu/node_modules/flatiron/lib/flatiron/plugins/cli.js",
      "function": "executeCommand",
      "line": 179,
      "method": null,
      "native": false
    },
    {
      "column": 5,
      "file": "/Users/mikl/Work/Node/knigu/node_modules/flatiron/lib/flatiron/plugins/cli.js",
      "function": "",
      "line": 224,
      "method": null,
      "native": false
    },
    {
      "column": 21,
      "file": "Object].dispatch (/Users/mikl/Work/Node/knigu/node_modules/flatiron/node_modules/director/lib/director/cli.js",
      "function": "[object",
      "line": 50,
      "method": null,
      "native": false
    },
    {
      "column": 18,
      "file": "/Users/mikl/Work/Node/knigu/node_modules/flatiron/lib/flatiron/plugins/cli.js",
      "function": null,
      "line": 58,
      "method": null,
      "native": false
    }
  ],
  "stack": [
    "TypeError: Object.keys called on non-object",
    "    at Function.keys (native)",
    "    at /Users/mikl/Work/Node/knigu/node_modules/nconf/lib/nconf/common.js:97:12",
    "    at Array.forEach (native)",
    "    at Object.merge (/Users/mikl/Work/Node/knigu/node_modules/nconf/lib/nconf/common.js:95:8)",
    "    at [object Object].save (/Users/mikl/Work/Node/knigu/node_modules/nconf/lib/nconf/provider.js:415:19)",
    "    at /Users/mikl/Work/Node/knigu/lib/commands/generate_chapter_pointers.js:18:9",
    "    at executeCommand (/Users/mikl/Work/Node/knigu/node_modules/flatiron/lib/flatiron/plugins/cli.js:179:19)",
    "    at Object.<anonymous> (/Users/mikl/Work/Node/knigu/node_modules/flatiron/lib/flatiron/plugins/cli.js:224:5)",
    "    at [object Object].dispatch (/Users/mikl/Work/Node/knigu/node_modules/flatiron/node_modules/director/lib/director/cli.js:50:21)",
    "    at /Users/mikl/Work/Node/knigu/node_modules/flatiron/lib/flatiron/plugins/cli.js:58:18"
  ],
  "level": "error",
  "message": "uncaughtException"
}

Using `defaults`, `env` or `argv` causes save to fail

Having a .defaults call in the chain causes save to fail with an exception as below. The same happens with either .env or .argv present. The examples seem to indicate this should be a valid way to use nconf.

jb@jborg-mbp:~/tmp % npm list
/Users/jb/tmp
└─┬ [email protected] 
  ├── [email protected] 
  ├── [email protected] 
  ├─┬ [email protected] 
  │ └── [email protected] 
  └── [email protected] 

jb@jborg-mbp:~/tmp % cat test.js 
var nconf = require('nconf');
nconf.file({ file: 'settings.json' });
nconf.defaults({
    foo: 'bar'
});
nconf.save();
jb@jborg-mbp:~/tmp % node test.js 

/Users/jb/tmp/node_modules/nconf/lib/nconf/common.js:96
    Object.keys(obj).forEach(function (key) {
           ^
TypeError: Object.keys called on non-object
    at Function.keys (native)
    at /Users/jb/tmp/node_modules/nconf/lib/nconf/common.js:96:12
    at Array.forEach (native)
    at Object.merge (/Users/jb/tmp/node_modules/nconf/lib/nconf/common.js:95:8)
    at [object Object].save (/Users/jb/tmp/node_modules/nconf/lib/nconf/provider.js:425:19)
    at Object.<anonymous> (/Users/jb/tmp/test.js:6:7)
    at Module._compile (module.js:446:26)
    at Object..js (module.js:464:10)
    at Module.load (module.js:353:31)
    at Function._load (module.js:311:12)

Live reload for power users

Hey...

I've found a lot of cases when i'd like to be able to set up a live reload of config options, without restarting the instance, e.g.
nconf.onChange ->
do stuff

or even fancier:
nconf.onChange (changeset?)->
do stuff

this might be a handy feature as part of the core functionality...

Unexpected nconf.overrides behaviour?

This works as expected, outputting Always be this value whatever the configuration for locals in config.json file:

nconf.overrides({ locals: 'Always be this value' });
nconf.file('./config/config.json');
console.log(nconf.get('locals'));

The following however will allow config.json to have extra keys for locals (foo is preserved, bar is merged):

nconf.overrides({ locals:{ 'foo': 'foo'} });
nconf.file('./config/config.json');
console.log(nconf.get('locals'));

File config.json:

{
    'locals': {
        'bar': 'bar'
    }
}

Is this a wanted behavior?

nconf in shared repository can't find file on server

Hi. I'm using nconf from a shared repository - my app code structure looks like this:

app
  node_modules
    shared
      node_modules
        nconf
      lib
        configuration.js
  config
    production.json
    development.json

When I'm doing this when I set up my config (in shared):

nconf.file(environment, "config/" + environment + ".json");

In development, my code can see my environment-specific config. In production (I'm on nodejitsu), my code can't see productions.json.

I'm using a private git repo for shared, and bundledDependencies in package.json.

How does nconf resolve file paths? I'm assuming cwd() ? If that is the case, any idea why I can't find my production.json but I can find development.json.

Thanks.

Wrong error description when parse error.

nconf.file({file: '/path/to/a/bad/format/ini/file', format: nconf.formats.ini})

parse bad ini file throws "Error parsing your JSON configuration file"

It made me confuse to debug.

Maybe "Error parsing /path/to/a/bad/format/ini/file configuration file" is better?

path.existsSync is now called `fs.existsSync`.

path.existsSync is deprecated since Node 0.7+, please change it to fs.existsSync on line 115 in file lib/nconf/stores/file.js :-)

Edit: Nevermind. For some reason I had nconf version 0.5.0 in use...

File override is not working

AppConfigDefaults.json:

{
    "dev": {
        "appRoot": "defaultAppRootDev"
    },
    "dist": {
        "appRoot": "defaultAppRootDist"
    }
}

AppConfigOverrides.json:

{
    "dev": {
        "appRoot": "overrideAppRootDev"
    }
}

Code:

nconf
    .file({file: 'AppConfigOverrides.json'})
    .file({file: 'AppConfigDefaults.json'});
console.log("dev.approot=" + nconf.get('dev').appRoot);
console.log("dist.approot=" + nconf.get('dist').appRoot);

prints:

dev.approot=defaultAppRootDev
dist.approot=defaultAppRootDist

Defaults file is not overridden by Overrides file for dev.approot.

Am I doing something wrong?

need way to get root of configs

right now conf.get(...) has no way to return the merged roots of all the stores, you can only go one level down and below.

conf.get(null) or conf.get(undefined) should most likely return the root of the config rather than complaining and throwing errors.

Memory Store in the chain of stores causes save to fail

I am currently using a memory store definition passed to child objects to keep readonly semantics on a global configuration file. However, calling save at the provider level results in the following exception:

TypeError: Object.keys called on non-object
    at Function.keys (native)
    at C:\util\build\node_modules\nconf\lib\nconf\common.js:96:12
    at Array.forEach (native)
    at Object.merge (C:\util\build\node_modules\nconf\lib\nconf\common.js:95:8)
    at [object Object].save (C:\util\build\node_modules\nconf\lib\nconf\provider.js:425:19)
    at...

Using a configuration hierarchy that looks something like:

    provider = new nconf.Provider({
        stores: [
            { name: 'workspace', type: 'file', file: 'workspace.json' },
            { name: 'buildId',   type: 'file', file: 'buildId.json' },
            { name: 'global',    type: 'memory', loadFrom: ['global.json'] }
        ]
    }); 

Calling save on the provider in turn triggers this logic:

  //
  // If we don't have a callback and the current 
  // store is capable of saving synchronously
  // then do so.
  //
  if (!callback) {
    return common.merge(names.map(saveStoreSync));
  }

The map function triggers saveStoreSync does the following:

    //
    // If the `store` doesn't have a `saveSync` method, 
    // just ignore it and continue. 
    //
    return store.saveSync
      ? store.saveSync()
      : null;

resulting in a null instead of the store object when the method saveSync is undefined on a particular store.

When common.merge is then called:

common.merge = function (objs) {
  var store = new Memory();

  objs.forEach(function (obj) {
    Object.keys(obj).forEach(function (key) {
      store.merge(key, obj[key]);
    });
  });

  return store.store;
};

No check is done on the store prior to using it resulting in the exception listed above.

My workaround for now is to monkey patch the memory store with dummy save/saveSync methods.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.