CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nconf

Hierarchical node.js configuration with files, environment variables, command-line arguments, and atomic object merging

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

utilities.mddocs/

Utilities and Validation

Utility functions for key manipulation, file loading, object merging, and configuration validation with required key checking. These utilities support nconf's hierarchical configuration system.

Capabilities

Required Key Validation

Validate that essential configuration keys are present and throw descriptive errors for missing keys.

/**
 * Validate that required configuration keys are present
 * @param {string[]} keys - Array of required key names (supports nested keys)
 * @throws {Error} Throws error with missing key names if validation fails
 * @returns {boolean} Returns true if all keys are present
 */
required(keys);

Usage Examples:

const nconf = require('nconf');

// Basic required key validation
try {
  nconf.required(['database:host', 'database:port', 'jwt:secret']);
  console.log('All required configuration is present');
} catch (err) {
  console.error('Configuration error:', err.message);
  // Error: Missing required keys: jwt:secret
  process.exit(1);
}

// Application startup validation
const requiredKeys = [
  'NODE_ENV',           // Environment name
  'PORT',               // Server port
  'database:host',      // Database connection
  'database:port',
  'database:name',
  'redis:url',          // Cache connection
  'jwt:secret',         // Authentication secret
  'api:key'             // External API key
];

function validateConfiguration() {
  try {
    return nconf.required(requiredKeys);
  } catch (err) {
    console.error('\n❌ Configuration Validation Failed');
    console.error('Missing required keys:', err.message.replace('Missing required keys: ', ''));
    console.error('\nPlease check your environment variables and configuration files.\n');
    process.exit(1);
  }
}

// Service-specific validation
const databaseKeys = ['database:host', 'database:port', 'database:name'];
const redisKeys = ['redis:host', 'redis:port'];

if (nconf.get('features:database')) {
  nconf.required(databaseKeys);
}

if (nconf.get('features:caching')) {
  nconf.required(redisKeys);
}

Any Value Lookup

Get the first truthy value from a list of configuration keys, providing fallback behavior for configuration resolution.

/**
 * Get first truthy value from a list of keys
 * @param {string[]|...string} keys - Array of keys or variable arguments
 * @param {function} [callback] - Optional callback for async operation
 * @returns {*} First truthy value found or null if none found
 */
any(keys, callback);

Usage Examples:

// Array form with fallback keys
const dbHost = nconf.any(['DATABASE_HOST', 'DB_HOST', 'database:host']);
const apiKey = nconf.any(['API_KEY', 'EXTERNAL_API_KEY', 'api:key']);

// Variable arguments form
const port = nconf.any('PORT', 'HTTP_PORT', 'server:port', 'app:port');

// With default values
const timeout = nconf.any(['REQUEST_TIMEOUT', 'api:timeout']) || 5000;
const maxRetries = nconf.any(['MAX_RETRIES', 'retries:max']) || 3;

// Environment-specific configuration
const configFile = nconf.any([
  `config/${process.env.NODE_ENV}.json`,
  'config/default.json',
  './config.json'
]);

// Asynchronous form
nconf.any(['REDIS_URL', 'CACHE_URL', 'redis:url'], (err, value) => {
  if (err) {
    console.error('Error finding Redis URL:', err);
    return;
  }
  
  if (value) {
    console.log('Redis URL found:', value);
    connectToRedis(value);
  } else {
    console.log('No Redis URL configured, skipping cache setup');
  }
});

// Complex fallback logic
function getDatabaseConfig() {
  // Try full connection string first
  let dbUrl = nconf.any(['DATABASE_URL', 'DB_URL']);
  if (dbUrl) {
    return parseConnectionString(dbUrl);
  }
  
  // Fall back to individual components
  return {
    host: nconf.any(['DB_HOST', 'DATABASE_HOST']) || 'localhost',
    port: nconf.any(['DB_PORT', 'DATABASE_PORT']) || 5432,
    database: nconf.any(['DB_NAME', 'DATABASE_NAME']) || 'myapp',
    username: nconf.any(['DB_USER', 'DATABASE_USER']) || 'postgres'
  };
}

Reset Configuration

Clear all configuration data from all writable stores, useful for testing and reinitialization.

/**
 * Clear all configuration data from writable stores
 * @param {function} [callback] - Optional callback for async operation
 * @returns {Provider} Provider instance for chaining
 */
reset(callback);

Usage Examples:

// Synchronous reset
nconf.reset();
console.log('Configuration cleared');

// Asynchronous reset
nconf.reset((err) => {
  if (err) {
    console.error('Error clearing configuration:', err);
    return;
  }
  console.log('Configuration reset successfully');
  
  // Reload with fresh data
  nconf.load((loadErr) => {
    if (loadErr) console.error('Reload failed:', loadErr);
    else console.log('Configuration reloaded');
  });
});

// Reset and reconfigure pattern
function reconfigureApplication(newConfigPath) {
  nconf
    .reset()
    .file({ file: newConfigPath })
    .env()
    .argv();
    
  // Validate new configuration
  try {
    nconf.required(['database:host', 'app:port']);
    console.log('Application reconfigured successfully');
    return true;
  } catch (err) {
    console.error('Reconfiguration failed:', err.message);
    return false;
  }
}

// Testing utility
function cleanConfigForTest() {
  nconf.reset();
  nconf.defaults({
    env: 'test',
    database: {
      host: 'localhost',
      port: 5432,
      name: 'test_db'
    },
    logging: {
      level: 'error',
      silent: true
    }
  });
}

Static Utility Functions

Key Manipulation

Utilities for working with nconf's colon-delimited key system.

/**
 * Join arguments into colon-delimited key
 * @param {...string} args - Key segments to join  
 * @returns {string} Joined key with ':' delimiter
 */
nconf.key(...args);

/**
 * Split key into array using delimiter
 * @param {string} key - Key to split
 * @param {string} [separator=':'] - Delimiter to split on
 * @returns {string[]} Array of key segments
 */
nconf.path(key, separator);

/**
 * Join arguments with custom delimiter
 * @param {string} separator - Custom delimiter
 * @param {...string} args - Key segments to join
 * @returns {string} Joined key with custom delimiter
 */
nconf.keyed(separator, ...args);

Usage Examples:

// Key building
const dbKey = nconf.key('database', 'connections', 'primary');
// Result: 'database:connections:primary'

const cacheKey = nconf.key('cache', 'redis', 'cluster', '1');
// Result: 'cache:redis:cluster:1'

// Key parsing
const segments = nconf.path('database:host:primary');
// Result: ['database', 'host', 'primary']

const customSegments = nconf.path('app.server.port', '.');
// Result: ['app', 'server', 'port']

// Custom delimiter joining
const envKey = nconf.keyed('__', 'APP', 'DATABASE', 'HOST');
// Result: 'APP__DATABASE__HOST'

const dotKey = nconf.keyed('.', 'config', 'server', 'timeout');
// Result: 'config.server.timeout'

// Dynamic key construction
function buildConfigKey(service, environment, setting) {
  return nconf.key('services', service, environment, setting);
}

const redisHost = buildConfigKey('redis', 'production', 'host');
// Uses key: 'services:redis:production:host'

File Loading Utilities

Utility functions for loading and merging multiple configuration files.

/**
 * Load multiple files asynchronously and merge results
 * @param {string[]|Object} files - Array of file paths or options object
 * @param {function} callback - Callback with (err, mergedData)
 */
nconf.loadFiles(files, callback);

/**
 * Load multiple files synchronously and merge results  
 * @param {string[]|Object} files - Array of file paths or options object
 * @returns {Object} Merged configuration data
 */
nconf.loadFilesSync(files);

Usage Examples:

// Load multiple files asynchronously
const configFiles = [
  './config/default.json',
  './config/development.json',
  './config/local.json'
];

nconf.loadFiles(configFiles, (err, merged) => {
  if (err) {
    console.error('Failed to load config files:', err);
    return;
  }
  
  console.log('Merged configuration:', merged);
  // Files are merged in order, later files override earlier ones
});

// Load with custom format
nconf.loadFiles({
  files: ['./config.ini', './local.ini'],
  format: nconf.formats.ini
}, (err, data) => {
  if (err) throw err;
  console.log('INI config loaded:', data);
});

// Synchronous loading
try {
  const config = nconf.loadFilesSync([
    './config/base.json',
    `./config/${process.env.NODE_ENV}.json`
  ]);
  
  console.log('Configuration loaded:', config);
} catch (err) {
  console.error('Config load failed:', err.message);
  process.exit(1);
}

// Environment-specific loading
const env = process.env.NODE_ENV || 'development';
const configFiles = [
  './config/default.json',
  `./config/${env}.json`
];

// Add local override if it exists
const localConfig = './config/local.json';
if (require('fs').existsSync(localConfig)) {
  configFiles.push(localConfig);
}

const mergedConfig = nconf.loadFilesSync(configFiles);

Object Merging

Deep object merging utility used internally by nconf for combining configuration from multiple sources.

/**
 * Merge array of objects using Memory store
 * @param {Object[]} objs - Array of objects to merge
 * @returns {Object} Merged object with deep merging behavior
 */
nconf.merge(objs);

Usage Examples:

// Merge configuration objects
const baseConfig = { 
  app: { name: 'MyApp', port: 3000 },
  database: { host: 'localhost' }
};

const envConfig = {
  app: { port: 8080, debug: true },
  database: { port: 5432 }
};

const localConfig = {
  database: { password: 'secret' }
};

const merged = nconf.merge([baseConfig, envConfig, localConfig]);
// Result: {
//   app: { name: 'MyApp', port: 8080, debug: true },
//   database: { host: 'localhost', port: 5432, password: 'secret' }
// }

// Merge with arrays (arrays are replaced, not merged)
const config1 = { features: ['auth', 'logging'] };
const config2 = { features: ['metrics', 'monitoring'] };
const result = nconf.merge([config1, config2]);
// Result: { features: ['metrics', 'monitoring'] }

// Custom merging in application code
function mergeEnvironmentConfigs() {
  const configs = [];
  
  // Base configuration
  configs.push(require('./config/default.json'));
  
  // Environment-specific
  const env = process.env.NODE_ENV;
  if (env && env !== 'development') {
    configs.push(require(`./config/${env}.json`));
  }
  
  // Local overrides
  try {
    configs.push(require('./config/local.json'));
  } catch (err) {
    // Local config is optional
  }
  
  return nconf.merge(configs);
}

Value Parsing

Parse string values to native JavaScript types, useful for processing environment variables and command-line arguments.

/**
 * Parse string value to native type
 * @param {string} value - String value to parse
 * @returns {*} Parsed value (boolean, number, object, array, undefined, or original string)
 */
nconf.parseValues(value);

Usage Examples:

// Basic value parsing
console.log(nconf.parseValues('true'));      // boolean: true
console.log(nconf.parseValues('false'));     // boolean: false
console.log(nconf.parseValues('123'));       // number: 123
console.log(nconf.parseValues('3.14'));      // number: 3.14
console.log(nconf.parseValues('undefined')); // undefined
console.log(nconf.parseValues('null'));      // null
console.log(nconf.parseValues('hello'));     // string: 'hello'

// JSON parsing
const jsonStr = '{"host":"localhost","port":5432}';
console.log(nconf.parseValues(jsonStr));
// Result: { host: 'localhost', port: 5432 }

const arrayStr = '["auth","logging","metrics"]';
console.log(nconf.parseValues(arrayStr));
// Result: ['auth', 'logging', 'metrics']

// Custom parsing utility
function parseEnvironmentValues(env) {
  const parsed = {};
  Object.keys(env).forEach(key => {
    parsed[key] = nconf.parseValues(env[key]);
  });
  return parsed;
}

// Usage with environment variables
const processEnv = parseEnvironmentValues(process.env);
console.log(processEnv.NODE_ENV);    // string
console.log(processEnv.PORT);        // number (if PORT=3000)
console.log(processEnv.DEBUG);       // boolean (if DEBUG=true)

Transform Utilities

Helper for transforming key-value pairs during store loading.

/**
 * Transform object using transformation function
 * @param {Object} map - Object with key-value pairs
 * @param {function} fn - Transformation function  
 * @returns {Object} Transformed object
 */
nconf.transform(map, fn);

Usage Examples:

// Transform environment variables
const env = {
  'MYAPP_DATABASE_HOST': 'localhost',
  'MYAPP_DATABASE_PORT': '5432',
  'OTHER_VAR': 'ignored'
};

const transformed = nconf.transform(env, function(obj) {
  // Only process MYAPP_ prefixed variables
  if (!obj.key.startsWith('MYAPP_')) {
    return null;  // Skip this key-value pair
  }
  
  return {
    key: obj.key.replace('MYAPP_', '').toLowerCase().replace(/_/g, ':'),
    value: nconf.parseValues(obj.value)
  };
});

// Result: { 'database:host': 'localhost', 'database:port': 5432 }

// Transform configuration keys
const config = {
  'server-host': 'localhost',
  'server-port': '8080',
  'database-url': 'postgres://...'
};

const normalized = nconf.transform(config, function(obj) {
  return {
    key: obj.key.replace(/-/g, ':'),  // Convert kebab-case to colon notation
    value: obj.value
  };
});

// Result: { 'server:host': 'localhost', 'server:port': '8080', 'database:url': '...' }

Key Construction

Utility functions for constructing configuration keys with custom separators.

/**
 * Join arguments with custom separator
 * @param {string} separator - Separator to use between arguments
 * @param {...string} args - Arguments to join
 * @returns {string} Joined string with custom separator
 */
nconf.keyed(separator, ...args);

Usage Examples:

// Custom separator key construction
const key1 = nconf.keyed('__', 'database', 'connection', 'host');
// Result: 'database__connection__host'

const key2 = nconf.keyed('.', 'app', 'server', 'port');
// Result: 'app.server.port'

const key3 = nconf.keyed('/', 'config', 'environment', 'production');
// Result: 'config/environment/production'

// Dynamic key construction
function buildKey(separator, ...parts) {
  return nconf.keyed(separator, ...parts.filter(Boolean));
}

const dbKey = buildKey(':', 'database', process.env.NODE_ENV, 'host');
// Result: 'database:production:host' (if NODE_ENV=production)

// Build environment variable names
const envVar = nconf.keyed('_', 'MYAPP', 'DATABASE', 'HOST').toUpperCase();
// Result: 'MYAPP_DATABASE_HOST'

docs

argv-env.md

configuration.md

files.md

index.md

stores.md

utilities.md

tile.json