0
# Utilities and Validation
1
2
Utility functions for key manipulation, file loading, object merging, and configuration validation with required key checking. These utilities support nconf's hierarchical configuration system.
3
4
## Capabilities
5
6
### Required Key Validation
7
8
Validate that essential configuration keys are present and throw descriptive errors for missing keys.
9
10
```javascript { .api }
11
/**
12
* Validate that required configuration keys are present
13
* @param {string[]} keys - Array of required key names (supports nested keys)
14
* @throws {Error} Throws error with missing key names if validation fails
15
* @returns {boolean} Returns true if all keys are present
16
*/
17
required(keys);
18
```
19
20
**Usage Examples:**
21
22
```javascript
23
const nconf = require('nconf');
24
25
// Basic required key validation
26
try {
27
nconf.required(['database:host', 'database:port', 'jwt:secret']);
28
console.log('All required configuration is present');
29
} catch (err) {
30
console.error('Configuration error:', err.message);
31
// Error: Missing required keys: jwt:secret
32
process.exit(1);
33
}
34
35
// Application startup validation
36
const requiredKeys = [
37
'NODE_ENV', // Environment name
38
'PORT', // Server port
39
'database:host', // Database connection
40
'database:port',
41
'database:name',
42
'redis:url', // Cache connection
43
'jwt:secret', // Authentication secret
44
'api:key' // External API key
45
];
46
47
function validateConfiguration() {
48
try {
49
return nconf.required(requiredKeys);
50
} catch (err) {
51
console.error('\n❌ Configuration Validation Failed');
52
console.error('Missing required keys:', err.message.replace('Missing required keys: ', ''));
53
console.error('\nPlease check your environment variables and configuration files.\n');
54
process.exit(1);
55
}
56
}
57
58
// Service-specific validation
59
const databaseKeys = ['database:host', 'database:port', 'database:name'];
60
const redisKeys = ['redis:host', 'redis:port'];
61
62
if (nconf.get('features:database')) {
63
nconf.required(databaseKeys);
64
}
65
66
if (nconf.get('features:caching')) {
67
nconf.required(redisKeys);
68
}
69
```
70
71
### Any Value Lookup
72
73
Get the first truthy value from a list of configuration keys, providing fallback behavior for configuration resolution.
74
75
```javascript { .api }
76
/**
77
* Get first truthy value from a list of keys
78
* @param {string[]|...string} keys - Array of keys or variable arguments
79
* @param {function} [callback] - Optional callback for async operation
80
* @returns {*} First truthy value found or null if none found
81
*/
82
any(keys, callback);
83
```
84
85
**Usage Examples:**
86
87
```javascript
88
// Array form with fallback keys
89
const dbHost = nconf.any(['DATABASE_HOST', 'DB_HOST', 'database:host']);
90
const apiKey = nconf.any(['API_KEY', 'EXTERNAL_API_KEY', 'api:key']);
91
92
// Variable arguments form
93
const port = nconf.any('PORT', 'HTTP_PORT', 'server:port', 'app:port');
94
95
// With default values
96
const timeout = nconf.any(['REQUEST_TIMEOUT', 'api:timeout']) || 5000;
97
const maxRetries = nconf.any(['MAX_RETRIES', 'retries:max']) || 3;
98
99
// Environment-specific configuration
100
const configFile = nconf.any([
101
`config/${process.env.NODE_ENV}.json`,
102
'config/default.json',
103
'./config.json'
104
]);
105
106
// Asynchronous form
107
nconf.any(['REDIS_URL', 'CACHE_URL', 'redis:url'], (err, value) => {
108
if (err) {
109
console.error('Error finding Redis URL:', err);
110
return;
111
}
112
113
if (value) {
114
console.log('Redis URL found:', value);
115
connectToRedis(value);
116
} else {
117
console.log('No Redis URL configured, skipping cache setup');
118
}
119
});
120
121
// Complex fallback logic
122
function getDatabaseConfig() {
123
// Try full connection string first
124
let dbUrl = nconf.any(['DATABASE_URL', 'DB_URL']);
125
if (dbUrl) {
126
return parseConnectionString(dbUrl);
127
}
128
129
// Fall back to individual components
130
return {
131
host: nconf.any(['DB_HOST', 'DATABASE_HOST']) || 'localhost',
132
port: nconf.any(['DB_PORT', 'DATABASE_PORT']) || 5432,
133
database: nconf.any(['DB_NAME', 'DATABASE_NAME']) || 'myapp',
134
username: nconf.any(['DB_USER', 'DATABASE_USER']) || 'postgres'
135
};
136
}
137
```
138
139
### Reset Configuration
140
141
Clear all configuration data from all writable stores, useful for testing and reinitialization.
142
143
```javascript { .api }
144
/**
145
* Clear all configuration data from writable stores
146
* @param {function} [callback] - Optional callback for async operation
147
* @returns {Provider} Provider instance for chaining
148
*/
149
reset(callback);
150
```
151
152
**Usage Examples:**
153
154
```javascript
155
// Synchronous reset
156
nconf.reset();
157
console.log('Configuration cleared');
158
159
// Asynchronous reset
160
nconf.reset((err) => {
161
if (err) {
162
console.error('Error clearing configuration:', err);
163
return;
164
}
165
console.log('Configuration reset successfully');
166
167
// Reload with fresh data
168
nconf.load((loadErr) => {
169
if (loadErr) console.error('Reload failed:', loadErr);
170
else console.log('Configuration reloaded');
171
});
172
});
173
174
// Reset and reconfigure pattern
175
function reconfigureApplication(newConfigPath) {
176
nconf
177
.reset()
178
.file({ file: newConfigPath })
179
.env()
180
.argv();
181
182
// Validate new configuration
183
try {
184
nconf.required(['database:host', 'app:port']);
185
console.log('Application reconfigured successfully');
186
return true;
187
} catch (err) {
188
console.error('Reconfiguration failed:', err.message);
189
return false;
190
}
191
}
192
193
// Testing utility
194
function cleanConfigForTest() {
195
nconf.reset();
196
nconf.defaults({
197
env: 'test',
198
database: {
199
host: 'localhost',
200
port: 5432,
201
name: 'test_db'
202
},
203
logging: {
204
level: 'error',
205
silent: true
206
}
207
});
208
}
209
```
210
211
## Static Utility Functions
212
213
### Key Manipulation
214
215
Utilities for working with nconf's colon-delimited key system.
216
217
```javascript { .api }
218
/**
219
* Join arguments into colon-delimited key
220
* @param {...string} args - Key segments to join
221
* @returns {string} Joined key with ':' delimiter
222
*/
223
nconf.key(...args);
224
225
/**
226
* Split key into array using delimiter
227
* @param {string} key - Key to split
228
* @param {string} [separator=':'] - Delimiter to split on
229
* @returns {string[]} Array of key segments
230
*/
231
nconf.path(key, separator);
232
233
/**
234
* Join arguments with custom delimiter
235
* @param {string} separator - Custom delimiter
236
* @param {...string} args - Key segments to join
237
* @returns {string} Joined key with custom delimiter
238
*/
239
nconf.keyed(separator, ...args);
240
```
241
242
**Usage Examples:**
243
244
```javascript
245
// Key building
246
const dbKey = nconf.key('database', 'connections', 'primary');
247
// Result: 'database:connections:primary'
248
249
const cacheKey = nconf.key('cache', 'redis', 'cluster', '1');
250
// Result: 'cache:redis:cluster:1'
251
252
// Key parsing
253
const segments = nconf.path('database:host:primary');
254
// Result: ['database', 'host', 'primary']
255
256
const customSegments = nconf.path('app.server.port', '.');
257
// Result: ['app', 'server', 'port']
258
259
// Custom delimiter joining
260
const envKey = nconf.keyed('__', 'APP', 'DATABASE', 'HOST');
261
// Result: 'APP__DATABASE__HOST'
262
263
const dotKey = nconf.keyed('.', 'config', 'server', 'timeout');
264
// Result: 'config.server.timeout'
265
266
// Dynamic key construction
267
function buildConfigKey(service, environment, setting) {
268
return nconf.key('services', service, environment, setting);
269
}
270
271
const redisHost = buildConfigKey('redis', 'production', 'host');
272
// Uses key: 'services:redis:production:host'
273
```
274
275
### File Loading Utilities
276
277
Utility functions for loading and merging multiple configuration files.
278
279
```javascript { .api }
280
/**
281
* Load multiple files asynchronously and merge results
282
* @param {string[]|Object} files - Array of file paths or options object
283
* @param {function} callback - Callback with (err, mergedData)
284
*/
285
nconf.loadFiles(files, callback);
286
287
/**
288
* Load multiple files synchronously and merge results
289
* @param {string[]|Object} files - Array of file paths or options object
290
* @returns {Object} Merged configuration data
291
*/
292
nconf.loadFilesSync(files);
293
```
294
295
**Usage Examples:**
296
297
```javascript
298
// Load multiple files asynchronously
299
const configFiles = [
300
'./config/default.json',
301
'./config/development.json',
302
'./config/local.json'
303
];
304
305
nconf.loadFiles(configFiles, (err, merged) => {
306
if (err) {
307
console.error('Failed to load config files:', err);
308
return;
309
}
310
311
console.log('Merged configuration:', merged);
312
// Files are merged in order, later files override earlier ones
313
});
314
315
// Load with custom format
316
nconf.loadFiles({
317
files: ['./config.ini', './local.ini'],
318
format: nconf.formats.ini
319
}, (err, data) => {
320
if (err) throw err;
321
console.log('INI config loaded:', data);
322
});
323
324
// Synchronous loading
325
try {
326
const config = nconf.loadFilesSync([
327
'./config/base.json',
328
`./config/${process.env.NODE_ENV}.json`
329
]);
330
331
console.log('Configuration loaded:', config);
332
} catch (err) {
333
console.error('Config load failed:', err.message);
334
process.exit(1);
335
}
336
337
// Environment-specific loading
338
const env = process.env.NODE_ENV || 'development';
339
const configFiles = [
340
'./config/default.json',
341
`./config/${env}.json`
342
];
343
344
// Add local override if it exists
345
const localConfig = './config/local.json';
346
if (require('fs').existsSync(localConfig)) {
347
configFiles.push(localConfig);
348
}
349
350
const mergedConfig = nconf.loadFilesSync(configFiles);
351
```
352
353
### Object Merging
354
355
Deep object merging utility used internally by nconf for combining configuration from multiple sources.
356
357
```javascript { .api }
358
/**
359
* Merge array of objects using Memory store
360
* @param {Object[]} objs - Array of objects to merge
361
* @returns {Object} Merged object with deep merging behavior
362
*/
363
nconf.merge(objs);
364
```
365
366
**Usage Examples:**
367
368
```javascript
369
// Merge configuration objects
370
const baseConfig = {
371
app: { name: 'MyApp', port: 3000 },
372
database: { host: 'localhost' }
373
};
374
375
const envConfig = {
376
app: { port: 8080, debug: true },
377
database: { port: 5432 }
378
};
379
380
const localConfig = {
381
database: { password: 'secret' }
382
};
383
384
const merged = nconf.merge([baseConfig, envConfig, localConfig]);
385
// Result: {
386
// app: { name: 'MyApp', port: 8080, debug: true },
387
// database: { host: 'localhost', port: 5432, password: 'secret' }
388
// }
389
390
// Merge with arrays (arrays are replaced, not merged)
391
const config1 = { features: ['auth', 'logging'] };
392
const config2 = { features: ['metrics', 'monitoring'] };
393
const result = nconf.merge([config1, config2]);
394
// Result: { features: ['metrics', 'monitoring'] }
395
396
// Custom merging in application code
397
function mergeEnvironmentConfigs() {
398
const configs = [];
399
400
// Base configuration
401
configs.push(require('./config/default.json'));
402
403
// Environment-specific
404
const env = process.env.NODE_ENV;
405
if (env && env !== 'development') {
406
configs.push(require(`./config/${env}.json`));
407
}
408
409
// Local overrides
410
try {
411
configs.push(require('./config/local.json'));
412
} catch (err) {
413
// Local config is optional
414
}
415
416
return nconf.merge(configs);
417
}
418
```
419
420
### Value Parsing
421
422
Parse string values to native JavaScript types, useful for processing environment variables and command-line arguments.
423
424
```javascript { .api }
425
/**
426
* Parse string value to native type
427
* @param {string} value - String value to parse
428
* @returns {*} Parsed value (boolean, number, object, array, undefined, or original string)
429
*/
430
nconf.parseValues(value);
431
```
432
433
**Usage Examples:**
434
435
```javascript
436
// Basic value parsing
437
console.log(nconf.parseValues('true')); // boolean: true
438
console.log(nconf.parseValues('false')); // boolean: false
439
console.log(nconf.parseValues('123')); // number: 123
440
console.log(nconf.parseValues('3.14')); // number: 3.14
441
console.log(nconf.parseValues('undefined')); // undefined
442
console.log(nconf.parseValues('null')); // null
443
console.log(nconf.parseValues('hello')); // string: 'hello'
444
445
// JSON parsing
446
const jsonStr = '{"host":"localhost","port":5432}';
447
console.log(nconf.parseValues(jsonStr));
448
// Result: { host: 'localhost', port: 5432 }
449
450
const arrayStr = '["auth","logging","metrics"]';
451
console.log(nconf.parseValues(arrayStr));
452
// Result: ['auth', 'logging', 'metrics']
453
454
// Custom parsing utility
455
function parseEnvironmentValues(env) {
456
const parsed = {};
457
Object.keys(env).forEach(key => {
458
parsed[key] = nconf.parseValues(env[key]);
459
});
460
return parsed;
461
}
462
463
// Usage with environment variables
464
const processEnv = parseEnvironmentValues(process.env);
465
console.log(processEnv.NODE_ENV); // string
466
console.log(processEnv.PORT); // number (if PORT=3000)
467
console.log(processEnv.DEBUG); // boolean (if DEBUG=true)
468
```
469
470
## Transform Utilities
471
472
Helper for transforming key-value pairs during store loading.
473
474
```javascript { .api }
475
/**
476
* Transform object using transformation function
477
* @param {Object} map - Object with key-value pairs
478
* @param {function} fn - Transformation function
479
* @returns {Object} Transformed object
480
*/
481
nconf.transform(map, fn);
482
```
483
484
**Usage Examples:**
485
486
```javascript
487
// Transform environment variables
488
const env = {
489
'MYAPP_DATABASE_HOST': 'localhost',
490
'MYAPP_DATABASE_PORT': '5432',
491
'OTHER_VAR': 'ignored'
492
};
493
494
const transformed = nconf.transform(env, function(obj) {
495
// Only process MYAPP_ prefixed variables
496
if (!obj.key.startsWith('MYAPP_')) {
497
return null; // Skip this key-value pair
498
}
499
500
return {
501
key: obj.key.replace('MYAPP_', '').toLowerCase().replace(/_/g, ':'),
502
value: nconf.parseValues(obj.value)
503
};
504
});
505
506
// Result: { 'database:host': 'localhost', 'database:port': 5432 }
507
508
// Transform configuration keys
509
const config = {
510
'server-host': 'localhost',
511
'server-port': '8080',
512
'database-url': 'postgres://...'
513
};
514
515
const normalized = nconf.transform(config, function(obj) {
516
return {
517
key: obj.key.replace(/-/g, ':'), // Convert kebab-case to colon notation
518
value: obj.value
519
};
520
});
521
522
// Result: { 'server:host': 'localhost', 'server:port': '8080', 'database:url': '...' }
523
```
524
525
### Key Construction
526
527
Utility functions for constructing configuration keys with custom separators.
528
529
```javascript { .api }
530
/**
531
* Join arguments with custom separator
532
* @param {string} separator - Separator to use between arguments
533
* @param {...string} args - Arguments to join
534
* @returns {string} Joined string with custom separator
535
*/
536
nconf.keyed(separator, ...args);
537
```
538
539
**Usage Examples:**
540
541
```javascript
542
// Custom separator key construction
543
const key1 = nconf.keyed('__', 'database', 'connection', 'host');
544
// Result: 'database__connection__host'
545
546
const key2 = nconf.keyed('.', 'app', 'server', 'port');
547
// Result: 'app.server.port'
548
549
const key3 = nconf.keyed('/', 'config', 'environment', 'production');
550
// Result: 'config/environment/production'
551
552
// Dynamic key construction
553
function buildKey(separator, ...parts) {
554
return nconf.keyed(separator, ...parts.filter(Boolean));
555
}
556
557
const dbKey = buildKey(':', 'database', process.env.NODE_ENV, 'host');
558
// Result: 'database:production:host' (if NODE_ENV=production)
559
560
// Build environment variable names
561
const envVar = nconf.keyed('_', 'MYAPP', 'DATABASE', 'HOST').toUpperCase();
562
// Result: 'MYAPP_DATABASE_HOST'
563
```