Dynamic configuration values with variable support.
Works with yml
, json
, toml
config formats and anything that parsed down to a plain ol' javascript object
Configorama extends your configuration with a powerful variable system. It resolves configuration variables from:
- CLI options
- ENV variables
- File references
- Other Key/values in config
- Async/sync JS functions
- Any source you'd like...
See tests for more examples.
Click to expand
Async API:
const path = require('path')
const configorama = require('configorama')
const cliFlags = require('minimist')(process.argv.slice(2))
// Path to yaml/json/toml config
const myConfigFilePath = path.join(__dirname, 'config.yml')
const config = await configorama(myConfigFilePath, {
options: args
})
Sync API:
const path = require('path')
const configorama = require('configorama')
const cliFlags = require('minimist')(process.argv.slice(2))
// Path to yaml/json/toml config
const myConfigFilePath = path.join(__dirname, 'config.yml')
const config = configorama.sync(myConfigFilePath, {
options: cliFlags
})
apiKey: ${env:SECRET_KEY}
# Fallback to default value if env var not found
apiKeyWithFallback: ${env:SECRET_KEY, 'defaultApiKey'}
# CLI option. Example `cmd --stage dev` makes `bar: dev`
bar: ${opt:stage}
# Composed example makes `foo: dev-hello`
foo: ${opt:stage}-hello
# You can also provide a default value. If no --stage flag is provided, it will use 'dev'
foo: ${opt:stage, 'dev'}
foo: bar
zaz:
matazaz: 1
wow:
cool: 2
# Self file reference. Resolves to `bar`
one: ${self:foo}
# Shorthand self reference. Resolves to `bar`
two: ${foo}
# Dot prop reference will traverse the object. Resolves to `2`
three: ${zaz.wow.cool}
# Import full yml/json/toml file via relative path
fileRef: ${file(./subFile.yml)}
# Import sub values from files. This imports other-config.yml `topLevel:` value
fileValue: ${file(./other-config.yml):topLevel}
# Import sub values from files. This imports other-config.json `nested.value` value
fileValueSubKey: ${file(./other-config.json):nested.value}
# Fallback to default value if file not found
fallbackValueExample: ${file(./not-found.yml), 'fall back value'}
asyncJSValue: ${file(./async-value.js)}
# resolves to 'asyncval'
${file(./asyncValue.js)}
will call into async-value
and run/resolve the async function with values. These values can be strings, objects, arrays, whatever.
/* async-value.js */
function delay(t, v) {
return new Promise((resolve) => setTimeout(resolve.bind(null, v), t))
}
async function fetchSecretsFromRemoteStore(config) {
await delay(1000)
return 'asyncval'
}
module.exports = fetchSecretsFromRemoteStore
Resolve values from cwd
git data.
########################
# Git Variables
########################
# Repo owner/name. E.g. DavidWells/configorama
repo: ${git:repo}
repository: ${git:repository}
# Repo owner. E.g. DavidWells
owner: ${git:owner}
repoOwner: ${git:repoOwner}
repoOwnerDashed: ${git:repo-owner}
# Url. E.g. https://github.com/DavidWells/configorama
url: ${git:url}
repoUrl: ${git:repoUrl}
repoUrlDashed: ${git:repo-url}
# Directory. E.g. https://github.com/DavidWells/configorama/tree/master/tests/gitVariables
dir: ${git:dir}
directory: ${git:directory}
# Branch
branch: ${git:branch}
# Commits. E.g. 785fa6b982d67b079d53099d57c27fa87c075211
commit: ${git:commit}
# Sha1. E.g. 785fa6b
sha1: ${git:sha1}
# Message. E.g. 'Initial commit'
message: ${git:message}
# Remotes. E.g. https://github.com/DavidWells/configorama
remote: ${git:remote}
remoteDefined: ${git:remote('origin')}
remoteDefinedNoQuotes: ${git:remote(origin)}
# Tags. E.g. v0.5.2-1-g785fa6b
tag: ${git:tag}
# Describe. E.g. v0.5.2-1-g785fa6b
describe: ${git:describe}
# Timestamp. E.g. 2025-01-28T07:28:53.000Z
gitTimestampRelativePath: ${git:timestamp('../../package.json')}
# Timestamp. E.g. 2025-01-28T07:28:53.000Z
gitTimestampAbsolutePath: ${git:timestamp('package.json')}
Filters will transform the resolved variables
toUpperCaseString: ${'value' | toUpperCase }
toKebabCaseString: ${'valueHere' | toKebabCase }
key: lol_hi
keyTwo: lol_hi
toKebabCase: ${key | toKebabCase }
toCamelCase: ${keyTwo | toCamelCase }
Functions will convert resolved config values with various methods.
object:
one: once
two: twice
objectTwo:
three: third
four: fourth
mergeObjects: ${merge(${object}, ${objectTwo})}
See the tests folder for a bunch of examples!
Configorama allows you to bring your own variable sources.
There are 2 ways to resolve variables from custom sources.
-
Use the baked in javascript method for sync or aysnc resolution.
-
Add your own variable syntax and resolver.
const config = configorama('path/to/configFile', { variableSources: [{ // Match variables ${consul:xyz} match: RegExp(/^consul:/g), // Custom variable source. Must return a promise resolver: (varToProcess, opts, currentObject) => { // Make remote call to consul return Promise.resolve(varToProcess) } }] }) console.log(config)
This would match the following config:
key: ${consul:xyz}
Q: Why should I use this?
Never rendering a stale configuration file again!
Q: Does this work with serverless.yml
Yes it does. Using serverless.js
as your main entry point!
/* serverless.js */
const path = require('path')
const configorama = require('configorama')
const args = require('minimist')(process.argv.slice(2))
// Path to serverless config to be parsed
const yamlFile = path.join(__dirname, 'serverless.config.yml')
module.exports = configorama.sync(yamlFile, { options: args })
How is this different than the serverless variable system?
-
You can use it with any other tool you'd like. Just include
configorama
and go nuts. -
It's pluggable. Add whatever variable syntax/sources you wish.
-
Filters! You can filter values before they are resolved.
key: ${opt:stage | toUpperCase}
-
Cleaner self references
keyOne: subKey: hi # Before key: ${self:keyOne.subKey} # Now key: ${keyOne.subKey}
-
Numbers as defaults are supported
key: ${env:whatever, 2}
-
TOML, YML, JSON, etc support
Configorama will work on any configuration format that can be converted into a JS object.
Parse any config format and pass it into configorama.
-
Configorama has a number of built-in functions.
Build in functions can be used within expressions as another way to transform and combine values. These are similar to the operators but all follow a common syntax:
<FUNCTION NAME>(<ARGUMENT 1>, <ARGUMENT 2>)
example:
${merge('one', 'two')} => 'onetwo'
This is forked out of the serverless framework variable system.
Mad props to:
erikerikson, eahefnawy, HyperBrain, ac360, gcphost, pmuens, horike37, lorengordon, AndrewFarley, tobyhede, johncmckim, mangas, e-e-e, BasileTrujillo, miltador, sammarks, RafalWilinski, indieisaconcept, svdgraaf, infiniteluke, j0k3r, craigw, bsdkurt, aoskotsky-amplify, and all the other folks who contributed to the variable system.
Additionally these tools were very helpful: