@2colours/toml-env v0.1.0
toml-env

Node.JS dotenv-alike module using "env files" written in TOML
toml-env is a largely dotenv-compatible module written in Typescript that uses TOML to load configuration from a .env.toml file and exposes them via the process.env and process.envTyped fields.
- đą Install
- đī¸ Usage (.env.toml)
- đ´ Multiple Environments đ (dotenv legacy)
- đ Deploying (.env.vault) đ (dotenv legacy)
- đ Docs
- đ Prior art and thanks
đą Install
# using npm
npm install @2colours/toml-env --save
# using yarn
yarn add @2colours/toml-envđī¸ Usage
Create a .env.toml file in the folder where you start the entry point of your project (typically the root of the repository). This file should be a valid TOML file so strings should adhere to TOML's allowed string notations.
REMOTE_HOST='42.42.42.42'
API_TOKEN="bla42bla42bla42_"There are plenty of ways to load toml-env with the default configuration:
# using Node's --require flag, assuming index.js as entry point
node -r @2colours/toml-env/config index.js// within the source code, as soon as possible
require('@2colours/toml-env').config();
console.log(process.env.REMOTE_HOST);.. or using ES6
// within the source code, as soon as possible
import '@2colours/toml-env/config';After the loading of the package, the values from .env.toml are exposed under process.env and process.envTyped. The difference is that in process.env all values are stringified (TOML allows advanced types like dates, tables and arrays), while process.envTyped preserves the types using the native JS equivalents.
Format and parsing
toml-env uses a fully-fledged TOML parser to process the content of the configuration file. Everything can be used, within the limits of Javascript types. For more information, consult the underlying TOML parser library.
Preload
You can use the --require (-r) command line option to preload toml-env. By doing this, you do not need to require and load toml-env in your application code.
The configuration options below are supported as command line arguments in the format toml_env_config_<option>=value
$ node -r @2colours/toml-env/config your_script.js toml_env_config_path=/custom/path/to/.env.toml toml_env_config_debug=trueAdditionally, you can use environment variables to set configuration options. Command line arguments will precede these.
$ TOML_ENV_CONFIG_<OPTION>=value node -r @2colours/toml-env/config your_script.js$ TOML_ENV_CONFIG_ENCODING=latin1 TOML_ENV_CONFIG_DEBUG=true node -r @2colours/toml-env/config your_script.js toml_env_config_path=/custom/path/to/.env.tomlMultiple Environments
Notice: currently, this functionality is largely relying on the original functionality of dotenv, therefore the following parts are verbatim taken from the README of dotenv. To migrate the files, the following steps are required:
- Please make sure that your
.env.vaultfile is valid according to TOML syntax (e.g. string quoting). - Instead of
DOTENV_NAMES, useTOML_ENV_NAMESas the keys. - Rename the
.env.vaultfile to.env.toml.vaultor specify the path.
You need to manage your secrets across different environments and apply them as needed? Use a .env.vault file with a DOTENV_KEY.
Deploying
You need to deploy your secrets in a cloud-agnostic manner? Use a .env.vault file. See deploying .env.vault files.
đ´ Manage Multiple Environments
Use dotenvx or dotenv-vault.
dotenvx
Run any environment locally. Create a .env.ENVIRONMENT file and use --env-file to load it. It's straightforward, yet flexible.
$ echo "HELLO=production" > .env.production
$ echo "console.log('Hello ' + process.env.HELLO)" > index.js
$ dotenvx run --env-file=.env.production -- node index.js
Hello production
> ^^or with multiple .env files
$ echo "HELLO=local" > .env.local
$ echo "HELLO=World" > .env
$ echo "console.log('Hello ' + process.env.HELLO)" > index.js
$ dotenvx run --env-file=.env.local --env-file=.env -- node index.js
Hello localdotenv-vault
Edit your production environment variables.
$ npx dotenv-vault open productionRegenerate your .env.vault file.
$ npx dotenv-vault buildâšī¸ đ Vault Managed vs đģ Locally Managed: The above example, for brevity's sake, used the đ Vault Managed solution to manage your .env.vault file. You can instead use the đģ Locally Managed solution. Read more here. Our vision is that other platforms and orchestration tools adopt the .env.vault standard as they did the .env standard. We don't expect to be the only ones providing tooling to manage and generate .env.vault files.
Learn more at dotenv-vault: Manage Multiple Environments
đ Deploying
Use dotenvx or dotenv-vault.
dotenvx
Encrypt your secrets to a .env.vault file and load from it (recommended for production and ci).
$ echo "HELLO=World" > .env
$ echo "HELLO=production" > .env.production
$ echo "console.log('Hello ' + process.env.HELLO)" > index.js
$ dotenvx encrypt
[dotenvx][info] encrypted to .env.vault (.env,.env.production)
[dotenvx][info] keys added to .env.keys (DOTENV_KEY_PRODUCTION,DOTENV_KEY_PRODUCTION)
$ DOTENV_KEY='<dotenv_key_production>' dotenvx run -- node index.js
[dotenvx][info] loading env (1) from encrypted .env.vault
Hello production
^ :-]dotenv-vault
Encrypt your .env.vault file.
$ npx dotenv-vault buildFetch your production DOTENV_KEY.
$ npx dotenv-vault keys productionSet DOTENV_KEY on your server.
# heroku example
heroku config:set DOTENV_KEY=dotenv://:key_1234âĻ@dotenvx.com/vault/.env.vault?environment=productionThat's it! On deploy, your .env.vault file will be decrypted and its secrets injected as environment variables â just in time.
âšī¸ A note from Mot: Until recently, we did not have an opinion on how and where to store your secrets in production. We now strongly recommend generating a .env.vault file. It's the best way to prevent your secrets from being scattered across multiple servers and cloud providers â protecting you from breaches like the CircleCI breach. Also it unlocks interoperability WITHOUT native third-party integrations. Third-party integrations are increasingly risky to our industry. They may be the 'du jour' of today, but we imagine a better future.
Learn more at dotenv-vault: Deploying
đ Documentation
toml-env exposes four functions:
configparsepopulatedecrypt
Config
config will read your .env.toml file, parse the contents, assign it to process.env (all values stringified) and process.envTyped (all values as JS equivalents of TOML types) and return an Object with a parsed key containing the loaded content (either the stringified one or the typed one) or an error key if it failed.
const result = tomlEnv.config();
if (result.error) {
throw result.error;
}
console.log(result.parsed);You can additionally, pass options to config.
Options
path
Default: path.resolve(process.cwd(), '.env.toml')
Specify a custom path if your file is located elsewhere.
require('@2colours/toml-env').config({ path: '/custom/path/to/.env.toml' });By default, config will look for a file called .env.toml in the current working directory.
Pass in multiple files as an array, and they will be parsed in order and combined into process.env and process.envTyped (or option.processEnv and option.processEnvTyped respectively, if set). By default, once a key has been set a value, instances of that same key in subsequent files are ignored. To override the value of a key with each subsequent file, set options.override to true.
require('@2colours/toml-env').config({ path: ['.env.toml.local', '.env.toml'] });encoding
Default: utf8
Specify the encoding of your file containing environment variables.
require('@2colours/toml-env').config({ encoding: 'latin1' });debug
Default: false
Turn on logging to help debug why certain keys or values are not being set as you expect.
require('@2colours/toml-env').config({ debug: process.env.DEBUG });override
Default: false
Override any environment variables that have already been set on your machine with values from your .env file(s).
When providing multiple files in options.path, this option will also tell toml-env to override the value of a key upon encountering a duplicate definition.
require('@2colours/toml-env').config({ override: true });processEnv
Default: process.env
Specify an object to write your (stringified) secrets to. Defaults to process.env environment variables.
const myObject = {};
require('@2colours/toml-env').config({ processEnv: myObject });
console.log(myObject); // values from .env.toml or .env.toml.vault live here now.
console.log(process.env); // this was not changed or written toprocessEnvTyped
Default: process.envTyped
Specify an object to write your (typed) secrets to. Defaults to the monkey-patched process.envTyped property.
const myObject = {};
require('@2colours/toml-env').config({ processEnvTyped: myObject });
console.log(myObject); // values from .env.toml or .env.toml.vault live here now.
console.log(process.envTyped); // this was not changed or written toTOML_ENV_KEY
Default: process.env.TOML_ENV_KEY
Pass the TOML_ENV_KEY directly to config options. Defaults to looking for process.env.TOML_ENV_KEY environment variable. Note this only applies to decrypting .env.toml.vault files. If passed as null or undefined, or not passed at all, toml-env falls back to its traditional job of parsing a .env.toml file.
require('@2colours/toml-env').config({ TOML_ENV_KEY: 'toml-env://:key_1234âĻ@dotenvx.com/vault/.env.vault?environment=production' })Parse
The underlying TOML parser exposed as is. Unlike for dotenv, it only accepts strings. Please consult the official repository for further information.
const tomlEnv = require('@2colours/toml-env');
const rawData = `point = { x = 1, y = 2 }
names = ['Alfred', 'Dorothy', 'Kim']
`;
const config = tomlEnv.parse(rawData); // will return an object
// { point : { x : 1, y : 2}, names: ["Alfred", "Dorothy", "Kim"] }Populate
The engine which populates process.env and process.envTyped with the contents of your .env.toml file is available for use. It accepts a target, a source, and options. This is useful for power users who want to supply their own objects.
For example, customizing the source:
const tomlEnv = require('@2colours/toml-env');
const parsed = { HELLO: 'world' };
tomlEnv.populate(process.env, parsed);
console.log(process.env.HELLO); // worldFor example, customizing the source AND target:
const tomlEnv = require('@2colours/toml-env');
const parsed = { HELLO: 'universe' };
const target = { HELLO: 'world' }; // empty object
tomlEnv.populate(target, parsed, { override: true, debug: true });
console.log(target); // { HELLO: 'universe' }options
Debug
Default: false
Turn on logging to help debug why certain keys or values are not being populated as you expect.
override
Default: false
Override any environment variables that have already been set.
Decrypt
The engine which decrypts the ciphertext contents of your .env.vault file is available for use. It accepts a ciphertext and a decryption key. It uses AES-256-GCM encryption.
For example, decrypting a simple ciphertext:
const tomlEnv = require('@2colours/toml-env');
const ciphertext = 's7NYXa809k/bVSPwIAmJhPJmEGTtU0hG58hOZy7I0ix6y5HP8LsHBsZCYC/gw5DDFy5DgOcyd18R';
const decryptionKey = 'ddcaa26504cd70a6fef9801901c3981538563a1767c297cb8416e8a38c62fe00';
const decrypted = tomlEnv.decrypt(ciphertext, decryptionKey);
console.log(decrypted); // # development@v6\nALPHA="zeta"đ Prior art and thanks
The project is based on the idea, spec tests and source code of dotenv, its licensing terms are included in LICENSE.
Special thanks to the creators of smol-toml, a modern, performant and reliable TOML 1.0 compatible parser written in Typescript.
zaida04's tomlenv deserves to be mentioned as prior art. It has a different aim from toml-env:
tomlenvaims to contain only environment variables likedotenvand it only uses TOML segments for defining various environments in the same filetoml-envaims to extend over coredotenvfunctionality by allowing structured data in the file containing secrets, filling the gap between arbitrary configuration files and environment variables while trying to retain good compatibility withdotenvwhere appropriate