@mostajs/config
Author: Dr Hamid MADANI <drmdh@msn.com> License: AGPL-3.0-or-later
Environment variable loader with profile cascade for the MostaJS ecosystem.
One .env file, multiple profiles (TEST, DEV, STAGING, PROD), switched
via a single MOSTA_ENV variable.
Install
npm install @mostajs/config
Why
Instead of juggling .env.test, .env.development, .env.production and
forgetting to sync them, keep one .env with profile-prefixed overrides.
# .env — commit the non-secret keys
MOSTA_ENV=TEST # active profile
DB_DIALECT=sqlite # plain default (also the TEST default)
SGBD_URI=./data.sqlite
DEV_DB_DIALECT=postgres
DEV_SGBD_URI=postgres://localhost:5432/devdb
PROD_DB_DIALECT=mongodb
PROD_SGBD_URI=${MONGO_ATLAS_URI} # secrets come from the orchestrator
Resolution cascade (first non-empty wins) :
${MOSTA_ENV}_${key}${key}fallbackargundefined
Usage
import { getEnv, getEnvBool, getEnvNumber, getCurrentProfile } from '@mostajs/config';
// String with fallback
const dialect = getEnv('DB_DIALECT', 'sqlite');
// Boolean (only 'true' — case-insensitive — returns true)
const showSql = getEnvBool('DB_SHOW_SQL', false);
// Number with fallback
const poolSize = getEnvNumber('DB_POOL_SIZE', 10);
// Diagnostic
console.log(`Running in profile: ${getCurrentProfile() ?? 'none'}`);
Loading a .env file (v1.1.0, zero-dependency)
getEnv* read process.env. To populate it from a .env file without
dotenv, call loadEnv() once at startup:
import { loadEnv, getEnvNumber } from '@mostajs/config';
loadEnv(); // reads <cwd>/.env into process.env
loadEnv({ path: '/etc/app/.env', override: true });
const port = getEnvNumber('PORT', 3000);
- Never throws if the file is missing — returns
{ loaded: false }. - By default does not overwrite variables already in the environment
(the real env wins over the file); pass
override: trueto invert. parseEnv(content)is exposed for pure parsing (no side effect): handlesexportprefixes, single/double quotes (with\n \t \r \" \\escapes), and inline# commentson unquoted values (a#with no leading space is kept, so URLs / JSON / hashes are safe).
Silent fallback guarantee
The loader never throws on missing keys. If a profile override is absent,
it silently falls back to the plain variable or to the fallback argument.
Callers decide whether undefined is a fatal condition.
process.env.MOSTA_ENV = 'STAGING';
// Neither STAGING_REDIS_URL nor REDIS_URL defined
getEnv('REDIS_URL') // undefined (no throw)
getEnv('REDIS_URL', 'redis://...') // 'redis://...' (fallback)
Empty strings are treated as unset
To avoid accidental blank values silently propagating, an empty string in a profile override falls through to the plain variable :
TEST_DB_DIALECT=
DB_DIALECT=sqlite
getEnv('DB_DIALECT') // 'sqlite', not ''
Whitespace in MOSTA_ENV is trimmed
MOSTA_ENV= TEST
Resolves to profile TEST. getCurrentProfile() returns 'TEST'.
Naming convention
- Profile name → uppercase (
TEST,DEV,PROD,STAGING) - Variable name → UPPER_SNAKE_CASE (
DB_DIALECT,SGBD_URI,REDIS_URL) - Profiled key →
{PROFILE}_{VARIABLE}— underscore separator (TEST_DB_DIALECT, notTEST.DB_DIALECTbecause the dot is rejected by POSIX shells)
Testing
npm run build
npm test
License
AGPL-3.0-or-later. See LICENSE.