dotenvToken: base dotenv filename token (default .env).privateToken: private suffix token (default local).env: selected environment string (e.g. dev, test).paths: ordered list of directories to search (later paths override earlier)..env*, private is .env.<privateToken>*.getdotenv.config.* and getdotenv.config.local.* layered on top of file-derived dotenv.For each path, up to four files are merged in this order (later wins):
<dotenvToken> (e.g. .env)<dotenvToken>.<env> (e.g. .env.dev)<dotenvToken>.<privateToken> (e.g. .env.local)<dotenvToken>.<env>.<privateToken> (e.g. .env.dev.local)Missing files are silently ignored.
Expansion happens recursively in strings:
$VAR[:default]${VAR[:default]}Unknown vars become empty string unless a default is provided. Escaped dollar signs (\$) remain literal.
Use helpers when you need the exact semantics:
import { dotenvExpand, dotenvExpandAll } from '@karmaniverous/get-dotenv';
getDotenv()Use getDotenv() when you want “compose an env map” without the CLI host/plugin system.
import { getDotenv } from '@karmaniverous/get-dotenv';
const env = await getDotenv({
env: 'dev',
paths: ['./'],
});
console.log(env.APP_SETTING);
Dynamic variables (programmatic) without casts:
import { defineDynamic, getDotenv } from '@karmaniverous/get-dotenv';
type Vars = { APP_SETTING?: string; ENV_SETTING?: string };
const dynamic = defineDynamic<Vars, { GREETING: (v: Vars) => string }>({
GREETING: ({ APP_SETTING = '' }) => `Hello ${APP_SETTING}`,
});
const env = await getDotenv<Vars>({ env: 'dev', paths: ['./'], dynamic });
When using the shipped CLI host (or embedding it via createCli/GetDotenvCli), config discovery + overlays are always active.
getdotenv.config.json|yaml|yml|js|mjs|cjs|ts|mts|ctsgetdotenv.config.*getdotenv.config.local.*rootOptionDefaults?: { ... } (root CLI defaults; collapsed families). Keys:
env, defaultEnv, paths, dotenvToken, privateToken, dynamicPathshell, loadProcess, captureexcludeAll, excludeDynamic, excludeEnv, excludeGlobal, excludePrivate, excludePubliclog, debug, trace, strictoutputPathvars, varsAssignor, varsAssignorPattern, varsDelimiter, varsDelimiterPatternpathsDelimiter, pathsDelimiterPatternredact, redactPatternswarnEntropy, entropyThreshold, entropyMinLength, entropyWhitelistrootOptionVisibility?: { [rootKey]: boolean }scripts?: Record<string, string | { cmd: string; shell?: string | boolean }>vars?: Record<string, string> (global/public vars)envVars?: Record<string, Record<string, string>> (per-env/public vars)plugins?: Record<string, unknown> (per-plugin config slices)requiredKeys?: string[]dynamic?: Record<string, string | ((vars, env?) => string | undefined)>schema?: unknowndynamic > env > globallocal > publicproject > packaged > baseThe plugins map is keyed by the realized mount path (root alias excluded). Examples:
plugins.awsplugins['aws/whoami']The host ctx includes ctx.dotenvProvenance describing the history of every key (descriptor-only).
kind: 'file': path, scope (global/env), privacy (public/private).kind: 'config': scope, privacy, configScope (packaged/project).kind: 'vars': explicit CLI/programmatic overrides.kind: 'dynamic': dynamicSource (config | programmatic | dynamicPath).Ordering matches overlay precedence (last entry is effective).