Gathering detailed insights and metrics for unified-env
Gathering detailed insights and metrics for unified-env
Gathering detailed insights and metrics for unified-env
Gathering detailed insights and metrics for unified-env
@qiwi/uniconfig-plugin-env
Uniconfig environment variables API
@-xun/env
Unified environment resolution and validation for any JS runtime
@-xun/next-env
Unified environment resolution and validation for Next.js
@decentra/binary-node-env
Module to be used as unified binary environment across Node and Browser
An lightweight, zero dependency package to unify node environment variables using strong typing
npm install unified-env
Typescript
Module System
Node Version
NPM Version
TypeScript (97.72%)
JavaScript (2.01%)
Shell (0.28%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
2 Stars
31 Commits
1 Forks
1 Watchers
25 Branches
1 Contributors
Updated on Jan 15, 2025
Latest Version
1.1.2
Package Id
unified-env@1.1.2
Unpacked Size
117.28 kB
Size
30.04 kB
File Count
34
NPM Version
7.24.2
Node Version
16.16.0
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
An lightweight, zero dependency package to unify node environment variables using strong typings
Unified-Env aims to provide a way to ensure required, valid environment variables using TypeScript for a type-safe API. Problems it solves:
First, install from npm:
1npm insall unified-env 2# or yarn 3yarn add unified-env
Second, create a central file to use UnifiedEnv
(for example, src/environment.ts
) and create your env.
1import { UnifiedEnv } from 'unified-env'; 2 3const environment = new UnifiedEnv({ 4 APP_VAR: true, // `true` = a required, string 5 DB_USER: true, 6 DB_PASSWORD: true, 7 DB_HOST: true, 8 DB_NAME: true, 9 DB_PORT: { required: true, type: Number, acceptableValues: [2000, 3000, 4000] }, // a required number of 2000, 3000, or 4000 10 APP_PROD: { required: true, type: Boolean }, // a required boolean 11 APP_DEFAULT: { required: true, defaultValue: 'app default' } // required with a defaultt value 12}) 13 .env() // parse `process.env` 14 .argv() // parse `process.argv` 15 .file({ filePath: './.env' }) // parse an `.env` file (relative path) 16 .generate(); // generate the environment object 17 18export default environment;
The above UnifedEnv
will parse the process.env
, then process.argv
, and then an .env
file looking for those variables; and generate
a final environment object. It will throw an error if 1) any required variable is missing, 2) there was an error parsing a Boolean
or Number
value,
or 3) a value was not in the listed acceptableValues
array. The exported environment
constant will
be strongly typed to the passed in configuration.
Third, import your environment into other files that need env variables (for example, src/database.ts
)
1import { Client } from 'pg'; 2import environment from './environment'; 3 4/* `environment` will be strongly typed */ 5 6const client = new Client({ 7 user: environment.DB_USER, 8 host: environment.DB_HOST, 9 database: environment.DB_NAME, 10 password: environment.DB_PASSWORD, 11 port: environment.DB_PORT, 12}); 13 14export default client;
See Key Notes under Advanced Usage
*See Use Cases for more pracical examples
All keys listed in your UnifiedEnv
constructor are the variables that will be typed.
UnifiedEnv
constructor are the variables that will be typed. See Advanced Env Options.env()
, .argv()
, and/or .file()
, order will matter. See Order Matters.file()
filepath option is relative to __dirname
(ie. where you are calling your root node project from). See Parsing an Env File.generate()
must be called to generate the file env objectprocess.env
, process.argv
, and/or an .env
file that were not listed in the configuration, will NOT be in the environment object returned from generate()
. See parsing process.env
available.process.env
, process.argv
and .env
file keys are all treated the same. Example; if UnifiedEnv
has a configuration item of { MY_KEY: true }
and process.argv
has --my-key='hello'
, UnifiedEnv
will not match against that key.There are several advanced configuration options for desired variables.
1const env = new UnifiedEnv({ 2 /* acceptable configuration options */ 3 MY_VAR: true | { 4 required?: boolean, 5 type?: String | Number | Boolean, 6 defaultValue?: string | boolean | number, 7 acceptableValues?: (string | boolean | number)[], 8 tieBreaker?: 'env' | 'argv' | 'file' 9 } 10}, { 11 logLevel?: 'log' | 'debug' | 'info' | 'warn' | 'error', 12 logger?: ILogger 13});
Each key must be of the following type:
true
: will default to { required: true, type: String }
EnvOption
object: all options are optional. note: a blank object will be treated as true
required: boolean
: If true
, an error will be throw when .generate()
is called if the variable is not set. If false
, no error will be throwntype: String | Number | Boolean
: If String
(default), the variable will be returned as a string
. If Number
, the variable will be parsed to a number
(an error will be throw if parsing fails). If Boolean
, the variable will be parsed to a boolean
(an error will be throw if parsing fails)defaultValue: string | boolean | number
: If the key has not been set, this default value will be used. Ensure the defaultValue
matches the typeof the type
option (string
is default)acceptableValues: (string | boolean | number)[]
: The variable value must be a value found in this array. Ensure the defaultValue
matches the typeof the type
option (string
is default)tieBreaker: 'env' | 'argv' | 'file'
: The value from the listed tieBreaker
will always be used in the event of the same value coming from different sources. Example, process.env
has MY_VAR=hello
and process.argv
has --MY_VAR=goodbye
; if MY_VAR has a tieBreaker = 'argv'
, the value from process.argv
will always be used -- even if .env()
was called before .argv()
(See Order Matters for more details). In this example, MY_VAR will equal 'goodbye'
.Object
logLevel: 'log' | 'debug' | 'info' | 'warn' | 'error'
: (default: 'warn'
) will control what kind of logs are displayedlogger: ILogger
: (default console
) any object that implements an ILogger
interface
1interface ILogger { 2 log (...args: any[]): void; 3 debug (...args: any[]): void; 4 info (...args: any[]): void; 5 warn (...args: any[]): void; 6 error (...args: any[]): void; 7};
process.env
using .env()
UnifiedEnv
will check the process.env
keys for any matching key in the UnifiedEnv
configuration. Only keys that match will be parsed.
For example, if the process.env
has the following values:
1ENV=prod LOG_LEVEL=debug ts-node my-unified-env.ts
And the UnifiedEnv
configuration looks like:
1const env = new UnifiedEnv({ LOG_LEVEL: true }).env().generate(); 2export default env;
The exported env
will NOT has an ENV
property.
Note: this rule applies to both
.argv()
and.file()
process.argv
using .argv()
As mentioned in the Key Notes section, UnifiedEnv
does not handle casing differently for process.argv
keys.
The reason being twofold:
process.argv
uniquely. UnifiedEnv
is not trying to replicate those.UnifiedEnv
aims to be as simple, and straight forward as possible. Having different naming conventions only complicates using this (or any) library.For process.argv
usage, take the following example:
1const env = new UnifiedEnv({ 2 LOG_LEVEL: true, 3 DB_USERNAME: true, 4 DB_PASSWORD: true 5}) 6 .argv().generate(); 7 8export default env;
process.argv
would need to have the same matching keys. An example command line call may look like:
1ts-node my-example-env.ts --LOG_LEVEL=info --DB_USERNAME=user123 --DB_PASSWORD=secrect123
Some rules and common mistakes to help understand how UnifiedEnv
will parse process.argv
:
1# CASING MATTERS (only matches on exact case) 2# white space is trimmed if not in quotes 3 4# SINGLE VALUE 5--DEV # { DEV: 'true' } <- note, this will always be string unless you specific type: Boolean in the config 6--DEV=true # { DEV: 'true' } 7--DEV=false # { DEV: 'false' } 8--DEV true # { DEV: 'true' } 9--DEV false # { DEV: 'false' } 10--DEV is awesome # { dev: 'is awesome' } 11--DB 'some url ' # { dev: 'some url ' } 12 13# MULTI VALUES 14--DEV=true dat --PIE # { DEV: 'true dat', PIE: 'true' } 15--DEV --PIE apple # { DEV: 'true', PIE: 'apple' } 16--DEV --PIE apple with cherry # { DEV: 'true', PIE: 'apple with cherry' } 17 18# COMMON MISTAKES 19 # args must start with `--` 20mistake --OTHER_VALUE # { OTHER_VALUE: 'true' } 21 # if they do not start with `--`, they will be 22 # treated as a string for the previous value 23--DEV true -DB=mongo # { DEV: 'true -DB=mongo' } 24--DEV true DB=mongo # { DEV: 'true DB=mongo' } 25 26 # keys must be in format `--{key}` otherwise they will be treated 27 # as strings for the previous value 28--DEV false -- DB mysql # { DEV: 'false -- DB mysql' } 29-- DEV true # { } # no output since no initial key was found 30 31 # equals cannot have spaces 32--SECRET = 'top secret' # { SECRET: '= \'top secret\'' } 33 34 # missing or mismatching quotes 35--SECRET 'top secret" # { SECRET: "'top secret\"" } 36--SECRET 'top secret # { SECRET: "'top secret" }
.file(options)
Options
: optional object
filePath: string
: (default: ./.env
) relative file path to the .env
file. Relative to the starting node scriptencoding: string
: (default 'utf-8'
) file encodingfailIfNotFound: boolean
: (default false
) if the specified env file was not found, throw an error stopping all processingUnifiedEnv
follows the standard NAME=VALUE
configuration format for .env
. Notes about parsing:
KEY
s on every newline=
characterAn example, project:
.
├── .env
└── src
└── env.ts
In .env
LOG_LEVELS=debug
ENV=dev
In src/env.ts
1const env = new UnifiedEnv({ 2 LOG_LEVEL: true, 3 DB_USERNAME: true, 4 DB_PASSWORD: true 5}) 6 .file({ filePath: '../.env' }) // relative path 7 .generate(); 8 9export default env;
From root directory, running:
1ts-node src/env.ts
.generate()
Important notes about .generate()
:
.generate()
must be called to compile (or "generate") the final env object.env()
, .argv()
, or .file()
must be called first in order for any config to be generated.generate()
has been called, no other function can/should be called on UnifiedEnv
.generate()
can only be called onceImportant notes about order:
tieBreaker
scenarios)Take this example. Take an env.ts
environment file that will have the UnifiedEnv
configuration. If called with the following…
1MY_VAR=hello ts-node env.ts --MY_VAR=goodbye
With the following configuration, the .env()
MY_VAR
value will be used because it is called first:
1const env = new UnifiedEnv({ 2 MY_VAR: true 3}) 4 .env() 5 .argv() 6 .generate(); 7 8// env.MY_VAR === 'hello' 9 10export default env;
With a tieBreaker
set to argv
, the .argv()
MY_VAR
value will be always used:
1const env = new UnifiedEnv({ 2 MY_VAR: { required: true, tieBreaker: 'argv' } 3}) 4 .env() 5 .argv() 6 .generate(); 7 8// env.MY_VAR === 'goodbye' 9 10export default env;
Given the following app structure:
.
├── .env
├── environment.ts
└── app
└── main.ts
.env
ENV=prod
LOG_LEVEL=info
environment.ts
1const environment = new UnifiedEnv({ 2 ENV: { required: true, acceptableValues: ['dev', 'test', 'prod'], tieBreaker: 'env' }, 3 DB_PORT: { required: true, type: Number }, 4 LOG_LEVEL: { required: false }, 5 REFRESH_DB: { required: true, typ: Boolean, defaultValue: true } 6}) 7 .env() 8 .argv() 9 .file() // default is '.env' 10 .generate();
src/main.ts
1import environment from '../environment'; 2 3/* mock app setup */ 4const app = new MyApp({ 5 isProd: environment.ENV === 'prod', 6 logLevel: environment.LOG_LEVEL 7}); 8 9const db = new DB({ 10 port: environment.DB_PORT, 11 refreshDb: environment.REFRESH_DB 12});
Starting the application with the following will provide the necessary variables to UnifiedEnv
:
1ENV=prod ts-node src/main.ts --ENV=dev --DB_PORT=3456
UnifiedEnv
will generate the following object:
1{ 2 ENV: 'prod', // used 'env' tieBreaker 3 DB_PORT: 3456, // from argv 4 LOG_LEVEL: 'info', // from .env file 5 REFRESH_DB: true // from default value 6}
Heroku was the inspiration for UnifiedEnv
. It was easier for me to have an .env
file in my local working project, but in the Heroku
dashboard most environment variables are stored in process.env
commandline variables. I didn't want to have production level
.env
files stored in my repo so I always use those process.env
vars.
The issue I would run into would be I add a variable to my local .env
file, finish out the feature I was working on (sometimes would take a week or two,
push the code to Heroku, and have runtime errors because I forgot to set the new env vars in my test and/or prod Heroku apps. UnifiedEnv
helps to solve
that problem by allowing validation of env variables before app start up. See Use a Validation Script for more details on how to do that.
Most of us have been working on a new fature locally, add a new env variable, and then forget to add it to the test/production environment. We don't always catch the mistake until our new feature is running in that environment and starts throwing errors.
UnifiedEnv
can easily be configured to pre-check our env variables before our app is started. For example, Heroku has a Release Phase where tasks can be configured to run before the application is released. A simple use case for UnifiedEnv
to validate env variables before releasing is:
Example app structure:
.
├── src
│ ├── environment.ts
│ └── main.ts
├── package.json
└── Procfile
In src/environment.ts setup our UnifiedEnv
configuration:
1const environment = new UnifiedEnv({ 2 ENV: { required: true, acceptableValues: ['dev', 'test', 'prod'] }, 3 DB_CONN_STR: { required: true }, 4 LOG_LEVEL: { required: true, acceptableValues: ['debug', 'info', 'warn', 'error'] } 5}) 6 .env() 7 .argv() 8 .file() 9 .generate(); 10 11export default environment;
src/main.ts will do application bootstrap, but will import the environment.ts file:
1import environment from './environment'; 2// other imports 3 4// bootstrap application, etc
Add a script to package.json. All this script needs to do, is load the src/environment.ts
. Heroku will call the script will
all the configured variables in the Heroku dashboard.
1{ 2 "scripts": { 3 "validate-env": "ts-node src/environment.ts", 4 "start": "ts-node src/main.ts", // example startup script 5 // other scripts 6 } 7}
In Procfile, add a "release" step and the "web" step (See Heroku's Procfile docs):
release: npm run validate-env
web: npm run start
When the package.json
validate-env script is run, if any env variables are missing UnifiedEnv
will throw an error causing the "release" phase
to fail. Heroku will not release the application until that script passes. This is an excellent way to ensure all env variables are present before starting
an applicaiton in a server environment.
There are several samples with corresponding configuration files. To run the samples, clone the repo and install dependencies:
1# clone repo 2git clone https://github.com/djhouseknecht/unified-env.git 3# cd into directory 4cd ./unified-env 5# install dependencies 6npm install # or yarn
Run the following npm scripts:
1# sample using `process.argv` 2npm run sample:argv 3 4# sample using `process.env` 5npm run sample:env 6 7# sample that throws errors 8npm run sample:error 9 10# sample using an `.env` file 11npm run sample:file
Be sure to check out the scripts in package.json and the configuration:
Idea was originally designed to make heroku development and deployments easier. It is loosely based on dotenv and nconf
load()
function to push all env variables into the process.env
exclude
list?IEnvOption
false
support for non-required stringaltKeys: string[]
for alternate keys to look forfile()
-> add .json
supportIEnvOption
-> better typings (and validation) for defaultValue
and acceptableValues
utils#validateExpectedVariables()
-> write thisutils#finalTypesMatch()
-> write thisNo vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
dependency not pinned by hash detected -- score normalized to 3
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
Found 0/14 approved changesets -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
license file not detected
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
29 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More