CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-dotenv

Loads environment variables from .env file into process.env with support for encrypted .env.vault files

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

environment-population.mddocs/

Environment Population

Utility for merging parsed environment variables into target objects like process.env with flexible override options and conflict resolution.

Capabilities

Populate Function

Populates a target object (like process.env) with parsed environment variables from a source object.

/**
 * Populates target object with parsed environment variables
 * @param processEnv - Target object to populate (typically process.env)
 * @param parsed - Source object with key-value pairs to merge
 * @param options - Population options for override and debug behavior
 * @returns Object containing keys and values that were actually set
 */
function populate(
  processEnv: DotenvPopulateInput,
  parsed: DotenvPopulateInput,
  options?: DotenvConfigOptions
): DotenvPopulateOutput;

Usage Examples:

const dotenv = require('dotenv');

// Basic population
const parsed = { DATABASE_URL: 'postgres://localhost/mydb', API_KEY: 'secret' };
const populated = dotenv.populate(process.env, parsed);
console.log(populated);
// { DATABASE_URL: 'postgres://localhost/mydb', API_KEY: 'secret' }

// With override option
process.env.EXISTING_VAR = 'original';
const newVars = { EXISTING_VAR: 'updated', NEW_VAR: 'new' };
const result = dotenv.populate(process.env, newVars, { override: true });
console.log(result);
// { EXISTING_VAR: 'updated', NEW_VAR: 'new' }

// With debug logging
dotenv.populate(process.env, parsed, { debug: true });
// Logs: [dotenv@17.2.2][DEBUG] "DATABASE_URL" is already defined and was NOT overwritten

// Populate custom object
const config = {};
dotenv.populate(config, { NODE_ENV: 'development', PORT: '3000' });
console.log(config);
// { NODE_ENV: 'development', PORT: '3000' }

Population Options

Override Behavior

Control whether existing variables are overwritten.

interface OverrideOptions {
  /** Override existing environment variables (default: false) */
  override?: boolean;
}

Examples:

const dotenv = require('dotenv');

// Existing variable protection (default)
process.env.NODE_ENV = 'production';
dotenv.populate(process.env, { NODE_ENV: 'development' });
console.log(process.env.NODE_ENV); // 'production' (unchanged)

// Override existing variables
process.env.NODE_ENV = 'production';
dotenv.populate(process.env, { NODE_ENV: 'development' }, { override: true });
console.log(process.env.NODE_ENV); // 'development' (overridden)

// Mixed scenario
process.env.EXISTING = 'keep';
const result = dotenv.populate(process.env, {
  EXISTING: 'change',
  NEW_VAR: 'add'
}, { override: false });

console.log(result);
// { NEW_VAR: 'add' } - only new variables returned
console.log(process.env.EXISTING); // 'keep' (unchanged)
console.log(process.env.NEW_VAR);   // 'add' (set)

Debug Logging

Enable detailed logging of population behavior.

interface DebugOptions {
  /** Enable debug logging (default: false) */
  debug?: boolean;
}

Examples:

// Enable debug mode
process.env.EXISTING_VAR = 'original';
dotenv.populate(process.env, {
  EXISTING_VAR: 'new',
  FRESH_VAR: 'value'
}, { debug: true });

// Console output:
// [dotenv@17.2.2][DEBUG] "EXISTING_VAR" is already defined and was NOT overwritten
// [dotenv@17.2.2][DEBUG] "FRESH_VAR" set

// With override enabled
dotenv.populate(process.env, {
  EXISTING_VAR: 'updated'
}, { debug: true, override: true });

// Console output:
// [dotenv@17.2.2][DEBUG] "EXISTING_VAR" is already defined and WAS overwritten

Advanced Usage

Selective Population

Populate only specific variables based on conditions:

const dotenv = require('dotenv');

function populateSelective(target, source, filter) {
  const filtered = {};
  
  Object.keys(source).forEach(key => {
    if (filter(key, source[key])) {
      filtered[key] = source[key];
    }
  });
  
  return dotenv.populate(target, filtered);
}

// Only populate development variables
const devFilter = (key, value) => key.startsWith('DEV_') || key === 'NODE_ENV';
const config = {};
populateSelective(config, {
  DEV_DATABASE_URL: 'localhost:5432',
  PROD_DATABASE_URL: 'prod:5432',
  NODE_ENV: 'development',
  SECRET_KEY: 'secret'
}, devFilter);

console.log(config);
// { DEV_DATABASE_URL: 'localhost:5432', NODE_ENV: 'development' }

Population Chain

Chain multiple population operations:

const dotenv = require('dotenv');

function populateChain(target, ...sources) {
  const results = [];
  
  sources.forEach((sourceConfig, index) => {
    const { source, options = {} } = sourceConfig;
    const result = dotenv.populate(target, source, options);
    results.push({ step: index + 1, populated: result });
  });
  
  return results;
}

// Usage
const config = {};
const results = populateChain(config,
  { 
    source: { BASE_URL: 'http://localhost', PORT: '3000' },
    options: { debug: true }
  },
  { 
    source: { BASE_URL: 'https://production.com', ENV: 'prod' },
    options: { override: true, debug: true }
  }
);

console.log(config);
// { BASE_URL: 'https://production.com', PORT: '3000', ENV: 'prod' }

Type-Safe Population

Create type-safe wrappers for population:

const dotenv = require('dotenv');

class TypedEnvironment {
  constructor(target = {}) {
    this.env = target;
  }
  
  populate(source, options = {}) {
    return dotenv.populate(this.env, source, options);
  }
  
  getString(key, defaultValue = '') {
    return this.env[key] || defaultValue;
  }
  
  getNumber(key, defaultValue = 0) {
    const value = this.env[key];
    return value ? parseInt(value, 10) : defaultValue;
  }
  
  getBoolean(key, defaultValue = false) {
    const value = this.env[key];
    if (!value) return defaultValue;
    return ['true', '1', 'yes', 'on'].includes(value.toLowerCase());
  }
  
  getArray(key, separator = ',', defaultValue = []) {
    const value = this.env[key];
    return value ? value.split(separator).map(s => s.trim()) : defaultValue;
  }
}

// Usage
const env = new TypedEnvironment();
env.populate({
  PORT: '3000',
  DEBUG: 'true',
  FEATURES: 'auth,billing,analytics'
});

console.log(env.getNumber('PORT'));        // 3000
console.log(env.getBoolean('DEBUG'));      // true
console.log(env.getArray('FEATURES'));     // ['auth', 'billing', 'analytics']

Error Handling

Handle invalid inputs and edge cases:

const dotenv = require('dotenv');

try {
  // Invalid parsed object
  dotenv.populate(process.env, null);
} catch (error) {
  console.log(error.code);    // 'OBJECT_REQUIRED'
  console.log(error.message); // 'OBJECT_REQUIRED: Please check the processEnv argument being passed to populate'
}

try {
  // Invalid target object
  dotenv.populate(null, { KEY: 'value' });
} catch (error) {
  console.log('Population failed:', error.message);
}

// Safe populate function
function safePopulate(target, source, options = {}) {
  try {
    if (!target || typeof target !== 'object') {
      throw new Error('Target must be an object');
    }
    
    if (!source || typeof source !== 'object') {
      throw new Error('Source must be an object');
    }
    
    return dotenv.populate(target, source, options);
  } catch (error) {
    console.error('Population error:', error.message);
    return {};
  }
}

Return Types

interface DotenvPopulateInput {
  [name: string]: string;
}

interface DotenvPopulateOutput {
  [name: string]: string;
}

interface DotenvPopulateOptions {
  /** Enable debug logging (default: false) */
  debug?: boolean;
  /** Override existing environment variables (default: false) */
  override?: boolean;
}

The return value contains only the key-value pairs that were actually set in the target object:

process.env.EXISTING = 'keep';
const result = dotenv.populate(process.env, {
  EXISTING: 'change',  // Won't be set (no override)
  NEW_VAR: 'add'       // Will be set
});

console.log(result);
// { NEW_VAR: 'add' } - only variables that were actually set

Install with Tessl CLI

npx tessl i tessl/npm-dotenv

docs

environment-loading.md

environment-population.md

file-parsing.md

index.md

vault-decryption.md

tile.json