-
Notifications
You must be signed in to change notification settings - Fork 2
Utils EnvArgs
Environment variable and configuration loader with .env file and Docker secrets support.
envArgs provides secure, flexible loading of environment variables from multiple sources:
- System Environment: Access system env variables
- .env Files: Parse .env files with quote handling
- Docker Secrets: Load secrets from /run/secrets
- Permission-Aware: Skips a source instead of throwing when its permission isn't granted (Deno-only gating — Bun/Node have no equivalent and are always treated as granted)
-
Read-only result: wraps the merged variables in a
PrivateObjectwith mutations disabled —set/delete/clearsilently no-op rather than throw (notObject.freeze)
deno add @tundralibs/utilsenvArgs(envFilePath?: string, loadDockerSecrets?: boolean | string): PrivateObject<Record<string, string>>
Loads environment variables from multiple sources.
Parameters:
-
envFilePath— a directory (its.envis loaded) or a path ending in.env. Default:'./'. -
loadDockerSecrets—true(default) reads every file under/run/secretsas akey=filenamesecret;falsedisables Docker secrets entirely; a string overrides the secrets directory path (useful in tests).
Docker secrets loading is on by default — passing no second argument still reads
/run/secretswhen it exists and is readable. Passfalseexplicitly to opt out.
Returns: Immutable object with environment variables
Merge order (later overrides earlier, same key wins by source priority — not call order):
- System environment (needs
envpermission; Deno gates this viaDeno.permissions, Bun/Node have no equivalent gate and are always treated as granted) -
.envfile (needsreadpermission on the file) - Docker secrets directory (needs
readpermission on the directory)
A source with no permission is silently skipped — envArgs never
throws on a missing file, a malformed .env line, or denied
permission; you simply get a smaller result.
Typed as always-present, but not.
PrivateObject<Record<string, string>>.get('KEY')is typedstring, notstring | undefined— TypeScript'sRecord<string, string>assumes every key exists. A missing key still returnsundefinedat runtime despite the type. Guard withhas()or keep a??fallback; don't rely on the type to catch a missing variable.
import { envArgs } from '@tundralibs/utils';
const env = envArgs();
// Access variables
const dbHost = env.get('DB_HOST') ?? 'localhost';
const apiKey = env.get('API_KEY');
// Check existence
if (env.has('DEBUG')) {
console.log('Debug mode enabled');
}.env:
DB_HOST=localhost
DB_PORT=5432
API_KEY="secret-key-with-spaces"
DEBUG=true
MULTI_LINE="line1
line2"TypeScript:
import { envArgs } from '@tundralibs/utils';
const config = envArgs('./config/.env');
const dbConfig = {
host: config.get('DB_HOST'),
port: parseInt(config.get('DB_PORT') ?? '5432'),
apiKey: config.get('API_KEY'),
};Docker secrets are read from /run/secrets by default — no flag
needed:
import { envArgs } from '@tundralibs/utils';
const env = envArgs(); // Docker secrets loading is on by default
const dbPassword = env.get('db_password'); // From /run/secrets/db_passwordDisable it, or point at a different secrets directory (e.g. in tests):
import { envArgs } from '@tundralibs/utils';
const noSecrets = envArgs('./', false);
const customSecrets = envArgs('./', '/tmp/test-secrets');import { envArgs } from '@tundralibs/utils';
const env = envArgs();
// Get all keys
const keys = env.keys();
// Iterate over all variables
env.forEach((key, value) => {
if (key.startsWith('API_')) {
console.log(`${key}: ${value}`);
}
});# Comments are ignored
KEY=value
QUOTED="value with spaces"
EMPTY=
MULTILINE="line1
line2"-
Use Defaults: Provide fallback values with
??operator - Type Conversion: Parse numbers and booleans explicitly
- Validation: Check required variables at startup
- Security: Never log sensitive values
- Config - Multi-format configuration loader
- privateObject - Secure data encapsulation