Simple & Secure Config Management for Node.js
Define all your config in one place.
Strong Config will load the correct config file based on your NODE_ENV
❓...struggled with config drift between local, staging, prod...?
❓...forgot to update the production config after updating the development config?
❓...forgot to tell your teammates to update their local .env
files after you made a change?
❓...worried about leaking secrets by accidentally pushing your .env
files to GitHub?
❓...wished you could nest config values in your .env
just like in a JavaScript object?
❓...had a CI build fail due to environment variable issues?
.env
filesYou can define config files as JSON or YAML
Here is a raw config as you would create it during development:
# A top-level config value which will be available to your application
# as `config.logger`
**logger**:
# A nested value which will be available as `config.logger.level`
level: DEBUG
**auth**:
apiClientId: non-secret-client-id
# A secret value. Every key with a 'Secret' suffix will be
# encrypted by Strong Config (e.g. 'encryptMeSecret')
apiSecret: top-secret-api-credential
# A dynamic value that will be substituted at runtime with the respective
# value of the environment variable $SHELL
shell: ${SHELL}
Here is how an encrypted config file looks like after running strong-config encrypt
**logger**:
# This value remains as is because it doesn't have a 'Secret' suffix
level: DEBUG
**auth**:
apiClientId: non-secret-client-id
# This is now encrypted and safe to commit into version control :)
apiSecret: ENC[AES256_GCM,data:aeQ+hlVIah7WyJoVR/Jbkb6GLH7ihsV0D81+U++pkiWD0zeoRL/Oe9Q3Tz6j/TNvKKVDnohIMyw3UVjELOuSY+A==,iv:nVRZWogV4B7o=,tag:KrE2jssfP4uCvqq+pc/JyQ==,type:str]
# Also still the same value which will be substituted only at runtime
shell: ${SHELL}
# The below section is auto-generated by [sops](<https://github.com/mozilla/sops>) and contains important metadata to
# decrypt the config at runtime. **Do not manually edit or delete this section.**
**sops**:
gcp_kms:
- resource_id: projects/my-project/locations/europe-west1/keyRings/my-project-key-ring/cryptoKeys/my-strong-config-key
created_at: '2020-01-07T10:11:12Z'
enc: AiAAmdAgj1dw1XdD2MsVpvmA4Deo867hmcX2B3NDhe9BCF2axuZ18hJJFK9oBlE1BrD70djwqi+L8T+NRNVnGUP+1//w8cJATAfJ8W/cQZFcdFTqjezC+VYv9xYI8i1bRna4xfFo/INIJtFDR38ZH1nrQg==
lastmodified: '2020-01-07T10:11:12Z'
mac: ENC[AES256_GCM,data:ABcd1EF2gh3IJKl4MNOpQr5stuvWXYz6sBCDEfGhIjK=,iv:A1AaAAAaa111a1Aa111AA/aaaAaaAAaa+aAaAaAAAaA=,tag:AAaaA1a1aaaAa/aa11AaaA==,type:str]
encrypted_suffix: Secret
version: 3.5.0
Create a new Node.js app
mkdir -p strong-config-test/src
cd strong-config-test
git init
yarn init --yes
touch src/config.js
Install Strong Config
yarn add @strong-config/node
<aside>
💡 Sidenote: The Sops Binary
After package installation, Strong Config automatically runs a postinstall
script that checks for availability of the sops binary on your system. If it can't find the sops binary, it will try to download it to node_modules/.bin/sops
which is always part of $PATH
when you run yarn run
or npm run
scripts.
Alternatively, you can also install sops globally via brew install sops
(macOS). For other systems check the official sops releases on GitHub.
</aside>
Create a config file
# By default, strong-config uses the ./config folder.
# You can configure this to be a different folder via the [options](<https://www.notion.so/brickblock/Strong-Config-e5dc221a7da34ef5a020707618f2f2dc#311640a59e5d45b49eccf6e3d66e11e1>)
mkdir config
# We'll use YAML here, but JSON is also supported
echo "myFirstConfig: strong" > config/development.yml
echo "myFirstSecret: a development secret" >> config/development.yml
Load config in your application code
/* src/config.js, or anywhere else you want to use config values */
const StrongConfig = require('@strong-config/node')
// Instantiate StrongConfig, then decrypt and load config file
const config = new StrongConfig().getConfig()
// This will print "{ myFirstConfig: 'strong' }" to the console
console.log(config)
/*
* OPTIONAL (but recommended)
* Call `new StrongConfig()` just once in your application, then
* export the memoized config object for other files to import.
*
* If you call `new StrongConfig()` again from another file, it would
* work, but would read the config from disk again which is slower than
* loading it from memory.
*/
module.exports = config
Add yarn start
script to your package.json
{
...
"scripts": {
"start": "node src/config.js"
}
...
}
<aside>
🚨 Warning: If you try running node src/config.js
directly from your terminal, it will fail if you haven't installed sops
globally. Wrapping it in a yarn/npm script is safer because all yarn/npm scripts automatically load ./node_modules/.bin
in the $PATH
, where a local version of Sops has been downloaded to by the postinstall
hook.
</aside>
Run your app
Strong Config determines which config file to load based on the NODE_ENV
environment variable. If you'd like to use a different env var, this is configurable via the options.
# Start app in 'development' mode which loads ./config/**development**.yml
NODE_ENV=**development** yarn start
<aside>
🚨 Warning: If you omit setting NODE_ENV=your-env
then Strong Config will fail because it doesn't know which config file it's supposed to load.
</aside>
Add a production config
touch config/production.yml
with the following content:
myFirstConfig: strong in production
myFirstSecret: super-duper-production-secret
Add a pre-commit git hook to avoid checking in unencrypted secrets
Add Husky via yarn add --dev husky
, then add the following to your package.json
:
"husky": {
"hooks": {
"pre-commit": "strong-config check"
}
},
Now try committing a config file with a secret and see that Strong Config protects you:
Set up Encryption Provider Hook up your encryption key provider of choice. Check this deep dive on how to set up an encryption provider: Encryption