Overview
Have your configuration in one place, organized in a js native structure, possbily hirarchial, but still easily configurable and overideable by environment variables, as recommended by the Twelve-Factor App methodology
Your config objects can look like below, and still fully support environment variables:
{
port: 1234, // PORT=1234
isCors: true // IS_CORS=true
db: {
hostName: 'example.com', // DB__HOST_NAME=example.com
port: 4321, // DB__PORT=4321
},
friends: ['Adam', 'Rachel'], // FRIENDS__0=Adam FRIENDS__1=Rachel
}
This tiny and powerfull config library reads keys from the config object and searches proccess.env for corresponding keys according to a naming convension.
It allows your apps to use config objects that fully support literal objects, literal arrays, numbers, strings and booleans , while stil being configured/overidden by env vars.
Sample
config.js
const {mapEnv} = require('@welldone-software/env-config')
module.exports = mapEnv({
port: 1234,
db: {
hostName: 'example.com',
port: 4321,
user: '',
password: '',
},
friends: ['Adam', 'Rachel'],
isCors: true
})
Environment variables (specified in .env file or at runtime)
DB__HOST_NAME=mydomain.com
DB__PORT=3060
DB__USER=ADMIN
DB__PASSWORD=ygIYDG*&h8&ADSGH
IS_CORS=false
ANOTHER_KEY=anothervalue
FRIENDS__1=Sara
At runtime, the result will be
{
port: 1234,
db: {
hostName: 'mydomain.com',
port: 3060,
user: 'ADMIN',
password: 'ygIYDG*&h8&ADSGH',
},
friends: ['Adam', 'Sara'],
isCors: false
}
Installing
yarn add @welldone-software/env-config
# or the npm version:
npm i @welldone-software/env-config
Importing
import {mergeEnv, mapEnv, getEnvKeys, getDotEnvFileFormat} from '@welldone-software/env-config';
// or the node version:
const {mergeEnv, mapEnv, getEnvKeys, getDotEnvFileFormat} = require('@welldone-software/env-config');
API
mergeEnv(config: Object) : Object
Recrusively applies values from the environment (environment variables) onto the fileds of the config object parameter and returns the same object, after it has been changed.
Note: this changes the object itself, and breaches immutablity thus we recommend using mapEnv
.
mapEnv(config: Object) : Object
A pure function version of mergeEnv
. This keeps the config object parameter immutable. It creates and returns a new object which is a combination of the original config object values and the values applied from the environment.
getEnvKeys(config: Object) : string[]
A utility function that returns the list of environment keys expected/supported for a given config object.
getDotEnvFileFormat(config: Object) : string
A utility function that returns the dot env file (keys and values) for a given config object.
Conventions
JS
- The JS config object should be a literal object with
camalCase
members. - Object can be nested, aka have members which are objects themselves.
- Object fields can be of of either _Object, String, Boolean, Number or Array type.
ENV
- Environment variables are expected in
UPPER_SNAKE_CASE
convention. - A single underscore (
_
) singinfied a word change and is mapped to case changes in js'scamalCase
. - Two underscores (
__
) mean nesting, e.g. DB_SETTINGS__CONNECTION_STRING translated to dbSettings.connectionString - Boolean values are
true
andfalse
- Arrays values are modeled like sub objects, e.g.
VAR_NAME__0
. Note the double underscore.
Type resolution
Types are determined by defaults in the config object, so you should have a defalut value on each field of the config object. The type of the value will determine the type and shape expected of the corresponding evironment variable.
Advantages
- Single source of truth - one place to define all posibble config keys.
- Simple to use but still allows for rather complex configurations: not just strings and not just flat structures.
- Uses 'native' naming convention in each environment so configs look natural both in JS and in ENV.
- Much more readable than the alternative:
const port = proccess.env.PORT || 1000
Roadmap
- Add typing support (typescript and Flow)
- Support initial prefix (only merge prefixed env vars)