Configue is a config library to easily customize your app from argv, env, files and more.
npm install configue> CONFIGUE ALL THE THINGS \o/
[![npm version][npm-badge]][npm-url]
[![Build Status][ci-badge]][ci-url]
[![Coverage Status][coverage-badge]][coverage-url]
[![License: MIT][license-badge]][license-url]
[Configue] is a node.js config library to easily customize your app from argv, env, files and more.
It defines a conventional workflow to load a config from environment variables,
command line arguments, files, that you can easily configure and extend.
#### Table of Content
- About Configue
- Installation
- Usage
* How To
* Basic usage without customization
+ Basic Configue
+ Basic Async Configue
+ Passing By Options
* Retrieving values
+ Simple get
+ Retrieving Specified Object
- Load and getObject for punctual retrieval
- Models for frequent usage
+ Template string
+ Argv / Env direct access
* Usage with customization of the configuration workflow
+ Specifying Files
+ Using Protocalls(Shortstop protocols)
+ Passing options to nconf to configure argv and env
+ Joint options of argv and env to process the values
+ Disabling Steps
+ Step hooks
+ Custom Workflow
* Loading into Hapi
* Loading into express
- Configuration Recap
* Configuration Object
* Fluent builder
[Configue] builds up on [nconf] and its
Hierarchical configuration system.
It defines a list of _configuration steps_ that are executed in order.
Every property defined on a steps will shadow the same key in the following steps.
Quoting [nconf]:
> "The order in which you attach these configuration sources determines their priority in the hierarchy"
Here are the standard steps [Configue] does define:
- overrides : properties that would take precedence on all other steps
- argv : command line options
- configueFile : file specified by --configue in argv if any.
- env : environment variables
- file : config files
- defaults : default objects
The plugin loads the various configurations in order using _predefined steps_.
It starts by parsing argv then goes through the env and the files options
and finishes by loading the default config objects if any.
Hence why every option defined as an argument commandline will override defaults
and environment variables.
If --configue option is specified, the config the specified file holds would
be loaded after the argv and before the env. This is to enable you to save
many options in many files, and specify at launch with options you want to use.
Just add configue has a dependency installing it with npm, or with yarn.
npm install --save configue
yarn add configue
To use _Configue_ you need first to create an instance passing the option to the Configue(opts)
constructor. Resolving of the config is now done synchronously and automatically unless you specify
the defer: true option, or if you opt in for an async resolve.
In case of a problem with the configue options it will throw an Error.
See the following examples for concrete presentation.
js
const Configue = require('configue');const configue = new Configue();
const who = configue.get('who', 'World');
console.log(
Hello ${who});
`#### Basic Async Configue[↥]
`js
const Configue = require('configue');const configue = new Configue({async: true});
configue.resolve().then(() => {
const who = configue.get('who', 'World');
console.log(
Hello ${who});
});
`Async resolve is necessary for some advanced features like async hooks and [shortstop] protocols.
#### Passing By Options[↥]
You can specify the
who configue in different manners.
Here are some:`sh
node basic.js --who=Woman
configue through Env
export who=Man ; node basic.js
who=Human node basic.js
node basic.js --configue=my-who-conf.json
`examples folder.$3
You can retrieve values from the store in different manner, get is the most simple one.#### Simple
get[↥]To retrieve a configue value, use the
get method on the config holder.
It takes has argument the key of the argument. For nested value you need to
use : or . to deep access to value, or you can an array of keys.It's also possible to specify a default value in case key is
undefined.`js
configue.get('defined4sure');
configue.get('some:nested:value');
configue.get('some.other.nested.value');
configue.get(['yet', 'another', 'nested', 'value']);
configue.get('mightBeUndefined', 'default');
`You can also retrieve a list of value with
getAll, or the first non undefined value from a list with getFirst`js
configue.getAll('defined4sure', 'some:nested:value');
configue.getAll(['defined4sure', 'some:nested:value']);
configue.getAll(['some.other.nested.value', ['yet', 'another', 'nested', 'value']]);configue.getFirst('defined4sure', 'some:nested:value');
configue.getFirst(['defined4sure', 'some:nested:value'], optionalDefaultValue);
`#### Retrieving Specified Object[↥]
When you can to retrieve several values in the same time you can forge object so that they have structure you need.
##### Load and getObject for punctual retrieval[↥]
The two main methods are
load and getObject
- load by default return the whole merged config as an object. But you can give him a model that would be used
to craft an object. The model is a object whose leaves are configue keys, or array of configue key:
ex: {serverConfig: {host: 'app:server:host', port: 'PORT'}, ...}
- getObject that takes a list of key, and return an object formed by key / values`js
const {serverConfig} = configue.load({
serverConfig: {host: 'app:server:host', port: 'PORT'},
extraOptions: '...'
});const {file, prefix} = configue.getObject('file', 'prefix');
`##### Models for frequent usage[↥]
There are case where the forged object are to be used several times, and you dont want to query them over and over.
To do that you can predefined models in the configuration. These would be populated once during automatic resolved,
and they would be made accessible under the
_ key.`js
const configue = new Configue({
models: {
serverConfig: {host: 'app:server:host', port: 'PORT'},
otherModel: {a: 'a', b: '...'}
}
});
//...
console.log(configue._.serverConfig); // => host: ..., port: ...
`#### Template string[↥]
One last way you can get config value is via the
configue.template (aliased to configue.t).
This is a template function you can prefix a template string. The interpolated values will be keys of the
configue and then replaced by their value:`js
console.log(configue.tI will say ${'salute'} to ${'who'});
// => I will say Hello to You
// (supposing called with --salute=Hello --who=You)
`
You can defined default values by passing a default object to the template method:
`js
console.log(
configue.t({times: 2, who: 'World'})I will say ${'salute'} to ${'who'} ${'times'} times
);
// => I will say Hello to You 2 times
`#### Argv / Env direct access[↥]
For ease of the the
argv and env can be directly accessible from the configue instance:`js
console.log(configue.argv.host);
console.log(configue.env.HOME);
`Note that values are neither parsed nor transformed.
$3
#### Specifying Files[↥]
The files key can contain a single object or an array of objects containing a
file key containing the path to the config file.
The object can also reference a nconf plugin tasked with the formatting using the key format.Starting from 1.0 the formatter to use can be automatically deduced for standard files. Supported extensions are
json, yaml/yml but also properties/ini and json5 In that case you just need to specify the name of the file.`js
const Configue = require('configue');const configueOptions = {
disable: {argv: true},
files: [
{file: './config.json'},
{
file: './config.yaml',
format: require('nconf-yaml')
},
'my-own.properties'
]
};
const configue = new Configue(configueOptions);
`Note that if only one file is needed, its path can be directly given as options.
#### Using Protocalls(Shortstop protocols)[↥]
[Protocall]protocall is a library that help transform json values by interpreting their content.
Quoting documentation:
> it enables the use of protocols and handlers to enable identification and special handling of json values.
For instance value with the standard
env and file protocol,
env:MY_ENV_VARIABLE will be replaced with the value of MY_ENV_VARIABLE while value file:/some/path will be
resolved with the content of the given file.
For more details refer to the [protocall] project.To enable it, you just need to have
{async: true, protocall: true} in your Configue config object.By default Configue comes empowered with the protocols from [shortstop-handlers]:
env, file, path, exec, base64, require.You can customize behavior of protocall by passing a config object as option:
- You can add extra protocols via the
protocols options, by passing an object {$protocolName: $handler}
- You can also precise the baseDir for file, path, exec, require default handler. (default being current working directory)
- If you don't want the default protocols, use the noDefaultProtocols option.
- By default the Buffer are stringified by Configue, but you can choose to preserve them with the preserveBuffer option.For an example of configuration refer to the following examples using
this json file as part of the config.
#### Passing options to nconf to configure argv and env[↥]
You can provide options arguments to
argv (yargsunderneath), and env in order to customize the behavior
around command line argument and environment variables.
For more in depth readings see nconf options [here][nconf-options-argv-env]`js
const Configue = require('configue');const configueOptions = {
argv: {
f: {
alias: 'file',
demandOption: true,
default: '/etc/passwd',
describe: 'x marks the spot',
type: 'string'
}
},
env: ['HOME', 'PWD'] // whitelist
};
const configue = new Configue(configueOptions);
`#### Joint options of argv and env to process the values[↥]
It is possible to process the raw values you can get from the
argv and env step, with the parse, separator
ignorePrefix, normalize and transform options.First you can specify to parse values with the
parse option. Argv and Env value will be then parse,
which is convenient to pass simple json from the command line.A
separator option is there to indicate the token that will be used to split a key and consider it as a nested value.
This affects both the argv and env step. The value can be either a string, or a regexp such as '__' or /__|--/With
ignorePrefix you can list of prefix for argv and env variable you want to be removed. This is particulary useful
with environment variables that are prefixed with your app name.Also a
normalize option enables you to make the variable names uniform with the same case, while using the idiomatic
case for the argv flag name and env variable. (for instance --my-var and MY_VAR).
This option accept as config the name of case function of lodash, the most useful being camelCase which will
transform our both variable into myVar as we would like name the javascript variable.
(other options are kebabCase, startCase, snakeCase,upperCase, lowerCase)If you have more complex processing of the env/arg variable name or value, you can use the
transform option,
which accept a function ({key, value}) => ({key:someKey, value:someValue}) that will be passed to nconf. (cf [nconf doc][nconf-transform])
This will happen after the ignore prefix, and before the case normalisation.#### Disabling Steps[↥]
The argv and env steps can be skipped using the
disable object in options.`js
const configue = new Configue({disable: {argv: true}});
// ...
`There is no disabling for
overrides, files and default; you just have to don't provide the matching option.#### Step hooks[↥]
Every step (
overrides, argv, env, files, defaults) has a post hook available.
Those can be defined using the postHooks key and accept a function that take nconf.
In async mode those hooks can be asynchronous by returning a Promise.The special hooks
first enables you to respectively apply a function on nconf at the very beginning.`js
const configue = new Configue({
postHooks: {
first: function first(nconf) {
// Your code here
},
overrides: function postOverrides(nconf) {
// Your code here
},
argv: function postArgv(nconf) {
// Your code here
}
}
});
// Your code here
`#### Custom Workflow[↥]
If needed you can have your full custom configuration workflow,
simply by providing an object with the single key
customWorkflow
attached to a function taking the nconf object, and a done callback.`js
const configueOptions = {
customWorkflow(nconf, done) {
// my own config setting
}
};const configue = new Configue(configueOptions);
`If you use a
yargs instance, you can assign it to nconf._yargs so that argv
is directly accessible from configue.argvThought _Configue_ is usable without hapi, (it was originally just a _Hapi_ plugin),hapi
it can be easily loaded in to have the _configue_ being easily accessible from
the server, or the request.
To do this, you need to register the plugin. It takes care to resolve the config if
was not done due to defer.
`js
const Hapi = require('hapi');
const Configue = require('configue');
const configue = new Configue({some: 'complex config with a model connexion'});
const server = new Hapi.Server();
server.connection(configue._.connexion); // note usage of the model connexion with port in it.
server.register({register: configue.plugin()}, err => {
// starting the server or else
// access to the config
const config = server.configue('some'); // => 'config'
const configGet = server.configue.get('some'); // => 'config'
// Any other call to server.configue.getAsync/getFirst/getAll/getObject/template/load
// ...
});
`examples
A more complete example is available in folder.
Note it's possible to provide to configue.plugin() a decorateName so that you use a custom accessor on server or request.
Warning: the original plugin is made for the pre 17 version of hapi. If you are using hapi@17 or beyond,
please retrive the plugin with the plugin17() method as you can see in the example server.
express via it's middleware you can obtain by configue.middleware() you just haveapp.use()A example is available in the examples folder.
- customWorkflow: a function manipulating the nconf. This option is exclusive of all others
- argv: Config object for yargv, a map of config key with an object values (alias, demandOption, default,describe, type)
- env: The options for the nconf.env method that can be:
- an array of string, the whitelisted env method
- an object with key: match, whitelistdisable
- : A object with key argv and/or env attach to a boolean indicated whether the step should be disable.files
- : file or list of files. (object file, format)defaults
- : Object of key mapped to default values. (or array of them)overrides
- : Object of key mapped to overrides values.required
- : list of key that are required one way or anotherpostHooks
- : an object of (step: function hook)first
step being one of , overrides, argv, env, files defaultsparse
- : boolean to request parsing of argv/env valuetransform
- : a function to process argv and env valuesnormalize
- : the case name in which you want keys to be convertedignorePrefix
- : a prefix or list of them you want to be remove from key nameprotocall
- /shortstop: to activate and customize the protocall/shortstop protocols. (prefer protocall, shortstop is to be deprecated)async
- : to activate async mode which will defer resolvedefer
- : to defer automatic resolve in sync mode
For more details you can see the internals.schema in the configue-core.js file around the line 60
Instead to use the configuration object provided to the Configue constructor, you can use the fluent builder.get
This consist in chaining a list of configuration methods before to retrieve the instance to a method or via aresolve method.
Here is a simple example:
`js`
const configue = Configue.defaults({a: 1, b: '2'})
.parse(true)
.normalize('camelCase')
.get();withOption
You can provide a portion of option with the method as you can see in this example using resolve:
`js`
Configue.defaults({a: 1, b: '2'})
.withOptions({parse: true, normalize: 'camelCase'})
.protocall(true)
.resolve(configue => {
// here goes your code
});
Here is the builder function list, the function name being the name of the key in he object config (except the postHooks function and withOptions):argv, async, customWorkflow, defaults, overrides, disable, env, files, required, transform, parse, normalize, separator, protocallfirstHook
and , overridesHook, argvHook, envHook, filesHook, defaultsHook, withOptions`
[↥]
[↥]: #configue
[Configue]: https://github.com/AdrieanKhisbe/configue
[github-repo]: https://github.com/AdrieanKhisbe/configue
[nconf]: https://github.com/indexzero/nconf
[nconf-options-argv-env]: https://github.com/indexzero/nconf#argv
[nconf-transform]: https://github.com/indexzero/nconf#transform-functionobj
[protocall]: https://github.com/omni-tools/protocall
[shortstop]: https://github.com/krakenjs/shortstop
[shortstop-handlers]: https://github.com/krakenjs/shortstop-handlers
[npm-badge]: https://img.shields.io/npm/v/configue.svg
[npm-url]: https://npmjs.com/package/configue
[ci-badge]: https://github.com/AdrieanKhisbe/configue/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/AdrieanKhisbe/configue/actions
[coverage-badge]: https://codecov.io/gh/AdrieanKhisbe/configue/branch/master/graph/badge.svg
[coverage-url]: https://codecov.io/gh/AdrieanKhisbe/configue
[license-badge]: https://img.shields.io/badge/License-MIT-blue.svg
[license-url]: https://opensource.org/licenses/MIT