envset
run commands in an environment defined using a ini configuration file.
- Environment level configuration
- Similar Tools
- Examples
- Installation
- Documentation
- .envset File
- .envsetrc
- License
Application configuration is (usually) specific to an environment and will change between different build environments- e.g. app secrets for a staging environment are different than your production secrets.
The 12 factor app guidelines suggest you store your application's configuration in the environment.
Environment variables enable us to manage application configuration outside of our application code.
Application configuration usually are small and sensitive data such as API keys or tokens, database credentials, etc. However not all environment configuration have to be secrets, there might be build distribution specific values such as the application's base URL to build OAuth callbacks, a dependent service endpoint or anything that changes between development and production environments.
envset
helps you manage environment variables for multiple build environments.
The following command will run a Node.js application with a development
environment:
$ envset development -- node server.js
envset
will load the variables defined in the [development]
section of a local .envset
file and execute the command after the --
.
See the examples section for more details.
Inspired by daemontools' tool envdir and tools such as dotenv.
- Distributed as a single binary
- No dependencies in your codebase
- e.g.
dotenv-rails
anddotenv
1 for Node.js require you to use a library
- e.g.
- Support multiple environments in a single file
- Generates an example file with your current env vars to keep documentation updated.
- Interpolation of variable using POSIX variable expansion.
- Command expansion
- Define required variables and exit with error if not set
- By default the shell environment is not loaded in the context
Instead of having an .env
file per environment you can have one single .envset
file with one section per environment.
1: You an actually require the library outside of your project with the node -r
flag.
An .envset file could look like this:
[development]
APP_SECRET_TOKEN=4c038a0b-4ed9-44e6-8682-9c82d5b831fd
APP_REMOTE_SERVICE_KEY=07ed716a-078a-4327-8847-b86394f14575
[production]
APP_SECRET_TOKEN=796bca0f-2692-495b-a994-e8ce82cad55f
APP_REMOTE_SERVICE_KEY=5655969e-af9f-4ac5-b186-184f43468443
To use it, simply prefix the call to your program with envset
and the name of the environment section. The node app.js
will be running with the environment variables specified in the development section of the .envset file.
$ envset development -- node app.js
envset
will optionally restart your command if it exits with an error code.
There are three flags you can use to manage the restart behavior:
--restart
: Restart command on exit error, default totrue
.--max-restarts [int]
: Max times to restart command, defaults to3
.--forever
: If present restart the command for as long asenvset
is running.
All these can be configured using an .envsetrc
file.
This will restart the node app for a maximum of --max-restarts
.
$ envset development --restart --max-restarts 10 -- node app.js
You can execute commands that use environment variables in the command arguments.
Is important to note that you need to scape the variable so that it is not replaced in the shell as you call envset
. You can do so by using single quotes '
or the scape char \$
.
$ envset development -- say '${APP_ENV}'
$ envset development -- say \${APP_ENV}
Sometimes the command you want to run will assume that has access to predefined environment variables:
$ envset development -- spd-say '${APP_ENV}'
Failed to connect to Speech Dispatcher:
Error: Can't connect to unix socket ~/.cache/speech-dispatcher/speechd.sock: No such file or directory. Autospawn: Autospawn failed. Speech Dispatcher refused to start with error code, stating this as a reason:
exit status 1
By default the process in which envset
runs spd-say
in an isolated mode has no access to your shell.
You can control environment inheritance using two flags:
--isolated
: Inherit all parent environment variables--inherit
: Inherit specific parent environment variables
If you need the executed command to inherit the host's environment wholesale use the --isolated=false
flag.
$ envset development --isolated=false -- spd-say '${APP_ENV}'
Some commands might rely on a known environment variable set on your shell, for instance if you want to go run
:
$ envset development -- go run cmd/app/server.go
missing $GOPATH
You will get an error saying that $GOPATH
is not available. The --inherit
flag lets you specify a list of environment variable keys that will be inherited from the parent environment:
$ envset development -I=GOPATH -I=HOME -- go run cmd/app/server.go
You can overwrite environment variables without editing your .envset
file.
APP_NAME="New Name" envset development --isolated=false -- spd-say '${APP_NAME}'
If you want to make the variables defined in a env file to your running shell session use something like the following snippet.
$ eval $(envset development)
You can specify a list of required environment variables for your command using the --required
flag or its -R
alias.
Given the following env file:
[development]
APP_SECRET_TOKEN={{APP_SECRET_TOKEN}}
APP_REMOTE_SERVICE_KEY={{APP_REMOTE_SERVICE_KEY}}
If you run the following command:
$ envset development --required=BOOM -R BOOM2 -- node index.js
envset
will exit with an error and a message with the missing variables:
missing required keys: BOOM,BOOM2
If we run the envset template
command with the previous .envset file we generate a envset.example file:
[development]
APP_SECRET_TOKEN={{APP_SECRET_TOKEN}}
APP_REMOTE_SERVICE_KEY={{APP_REMOTE_SERVICE_KEY}}
[production]
APP_SECRET_TOKEN={{APP_SECRET_TOKEN}}
APP_REMOTE_SERVICE_KEY={{APP_REMOTE_SERVICE_KEY}}
You can load other environment files like .env
files:
$ envset --env-file=.env -- node index.js
The metadata
command will generate a JSON file capturing the values of the provided env file.
Note that envset metadata compare
will output to stderr in the case that both files do not match.
$ envset metadata compare --section=development .meta/data.json .meta/prod.data.json
You can omit the path to the local source metadata file and only pass the remote file you want to compare against, it will use the configured path:
$ envset metadata compare --section=development .meta/prod.data.json
Pretty output
• source: .meta/data.json
STATUS ENV KEY HASH
👻 Missing MY_APP_NAME 6d22b97ab7dd...
• target: .meta/env.staging.json
👍 target has no extra environment variables
• different values
STATUS ENV KEY HASH
❓ Different APP_ENV 2e9975854897...
❓ Different NEW_THING 8896f09440c1...
👻 Missing in source (1) | 🌱 Missing in target (1)
❓ Different values (2) | 🤷 Ignored Keys (0)
To have JSON output you can pass the --json
flag:
$ envset metadata compare --json -s development .meta/data.json .meta/prod.json
{
"name": "development",
"values": [
{
"key": "MY_APP_SECRET",
"hash": "aca50d5cf2f285a5a5c5469c8fe9df2540b9bea6905a23461b",
"comment": "different hash value"
},
{
"key": "MY_APP_NAME",
"hash": "6d22b97ab7dd929f1b30099dcacd3a8f883373cefbe4a59a05",
"comment": "missing in source"
}
]
}
When comparing metadata files you can optionally ignore some variables that you know will be different or will be missing. You can do pass --ignore
or -I
flag with the variable name:
$ envset metadata compare --section=development -I IGNORED_VAR .meta/prod.data.json
Add tap to brew:
$ brew tap goliatone/homebrew-tap
Install envset
:
$ brew install envset
$ export tag=<version>
$ cd /tmp
$ wget https://github.com/goliatone/go-envset/releases/download/v${tag}/envset_${tag}_linux_x86_64.deb
$ sudo dpkg -i envset_${tag}_linux_x86_64.deb
$ yum localinstall https://github.com/goliatone/go-envset/releases/download/v<version>/envset_<version>_linux_x86_64.rpm
$ wget https://github.com/goliatone/go-envset/releases/download/v<version>/envset_<version>_linux_x86_64.tar.gz
$ tar -C /usr/bin/ -xzvf envset_<version>_linux_x86_64.tar.gz envset
$ chmod +x /usr/bin/envset
envset
will look for a file defining different environments and make them available as commands.
[development]
APP_BASE_URL=https://localhost:3003
[production]
APP_BASE_URL=https://envset.sh
Your .envset
files can have global variables that you are not part of any section but can be used to do string interpolation in section's variable values.
The syntax to interpolate is %(KEY)s
.
VERSION=v0.6.2
[development]
APP_BASE_URL=https://localhost:3003
DOWNLOAD_URL=%(APP_BASE_URL)s/%(VERSION)s
[production]
APP_BASE_URL=https://envset.sh
DOWNLOAD_URL=%(APP_BASE_URL)s/%(VERSION)s
You can have a special section with comments and the content will not generate syntax errors.
The following is a list of the available commands:
- metadata
- compare
- template
envset
can interpolate variables using POSIX variable expansion in both the loaded environment file and the running command arguments.
[development]
CLIENT_NAME=$(whoami -f)
CLIENT_ID=${CLIENT_NAME}.devices.local
$ envset development -- node cli.js --user '${USER}'
If you type envset
without arguments it will display help and a list of supported environment names.
You can create an .envsetrc
file with configuration options for envset
.
The default .envsetrc
looks like this:
# Default configuration
filename=.envset
expand=true
isolated=true
export_environment=APP_ENV
restart=true
max_restarts=3
restart_forever=false
[metadata]
dir=.meta
file=data.json
print=true
json=false
[template]
dir=.
file=envset.example
[environments]
name=test
name=staging
name=production
name=development
[comments]
key=COMMENTS
key=DOCUMENTATION
Follows rc
standards.
The loaded files need to be valid ini
syntax.
[development]
APP_BASE_URL=https://localhost:3003
[production]
APP_BASE_URL=https://envset.sh
You can add a [required]
or [ignored]
section in your .envsetrc
:
[ignored]
development=MY_APP_NAME
development=MY_APP_SECRET
staging=MY_IGNORED_STAGING
[required]
development=MY_REQUIRED_APP_NAME
staging=MY_REQUIRED_VAR_STAGING
Copyright (c) 2015 goliatone Licensed under the MIT license.