Hardwired configuration loader that automatically discovers and merges configuration from multiple sources
npx @tessl/cli install tessl/npm-rc@1.2.0RC is a hardwired configuration loader for Node.js applications that automatically discovers and merges configuration from multiple sources including command line arguments, environment variables, configuration files in various formats (JSON and INI), and default values. It follows Unix-style configuration conventions with a predictable precedence order where command line arguments override environment variables, which override configuration files, which override defaults.
npm install rcconst rc = require('rc');For ESM:
import rc from 'rc';const rc = require('rc');
// Basic usage: provide app name and defaults
const config = rc('myapp', {
port: 8080,
host: 'localhost',
debug: false
});
console.log(config);
// Loads config from:
// 1. Command line: --port 3000 --debug
// 2. Environment: myapp_port=3000 myapp_debug=true
// 3. Config files: .myapprc, ~/.myapprc, /etc/myapprc
// 4. Defaults: { port: 8080, host: 'localhost', debug: false }Main configuration loader that discovers and merges configuration from multiple sources with Unix-style precedence rules.
/**
* Load and merge configuration from multiple sources
* @param {string} name - Application name for config file discovery
* @param {object|string} [defaults] - Default configuration object or JSON string
* @param {object} [argv] - Custom parsed argv object (defaults to process.argv)
* @param {function} [parse] - Custom parser function for config files
* @returns {object} Merged configuration object with optional configs/config properties
* @throws {Error} If name is not a string
*/
function rc(name, defaults, argv, parse);Configuration Sources (in precedence order):
--foo bar, --nested.key=value)${appname}_ (e.g., myapp_port=3000)
__ for nested properties (e.g., myapp_db__host=localhost → db.host)--config path/to/file.${appname}rc (searches up directory tree)$HOME/.${appname}rc$HOME/.${appname}/config$HOME/.config/${appname}$HOME/.config/${appname}/config/etc/${appname}rc/etc/${appname}/configUsage Examples:
const rc = require('rc');
// Simple usage with defaults
const conf = rc('myapp', {
port: 2468,
views: {
engine: 'jade'
}
});
// Custom argv parsing
const customConf = rc('myapp', defaults, {
port: 3000,
debug: true,
_: []
});
// Custom file parser
const strictConf = rc('myapp', defaults, null, (content) => {
return JSON.parse(content); // Only allow valid JSON
});Browser-only version that simply returns defaults since file system access is not available.
/**
* Browser version - returns defaults only (no file system access)
* @param {string} name - Application name (ignored in browser)
* @param {object} [defaults] - Default configuration object
* @returns {object} The defaults object
*/
function rc(name, defaults);Usage:
<script src="node_modules/rc/browser.js"></script>
<script>
// Browser usage
const config = rc('myapp', { theme: 'light' });
// Returns: { theme: 'light' }
</script>Executable CLI tool that loads configuration for a specified application and outputs JSON.
# Load config for specified app and output JSON
rc <appname>
# Example
rc myapp
# Outputs JSON configuration for 'myapp'RC supports both JSON and INI format configuration files without file extensions:
JSON Format (supports comments):
{
// Comments are supported via strip-json-comments
"port": 3000,
"database": {
"host": "localhost",
"port": 5432
}
}INI Format:
; Comments supported in INI format
port=3000
[database]
host=localhost
port=5432
; Nested sections supported
[server.ssl]
enabled=true
cert=/path/to/cert.pemThe configuration object returned by rc() contains:
interface ConfigResult {
// All merged configuration properties
[key: string]: any;
// Array of paths to config files that were found and loaded
configs?: string[];
// Path to the last (highest precedence) config file used
config?: string;
// Remaining command line arguments from minimist
_?: string[];
}Example return object:
{
"port": "3001",
"mode": "test",
"foo": "bar",
"_": [],
"configs": [
"/Users/user/myproject/.myapprc",
"/Users/user/.myapprc"
],
"config": "/Users/user/.myapprc"
}Environment variables are mapped to configuration properties using the following rules:
// Environment variable → Configuration property
myapp_port=3000 → { port: "3000" }
myapp_db__host=localhost → { db: { host: "localhost" } }
myapp_ssl__cert__path=/x → { ssl: { cert: { path: "/x" } } }Important: Configuration values from files and environment variables are always strings. Use type conversion utilities for strict type checking:
const config = rc('myapp', { port: 8080 });
// Convert strings to proper types
config.port = parseInt(config.port) || config.port;
config.debug = config.debug === 'true';
config.timeout = parseFloat(config.timeout) || config.timeout;
// Or use a utility like parse-strings-in-object
const parseStrings = require('parse-strings-in-object');
const typedConfig = parseStrings(config);RC throws errors in the following cases:
try {
const config = rc('myapp', defaults);
} catch (error) {
if (error.message.includes('name *must* be string')) {
console.error('App name must be a string');
}
// Handle other configuration loading errors
}RC uses synchronous file system operations (fs.statSync), so avoid using it in hot code paths such as request handlers. Load configuration once at application startup:
// Good: Load once at startup
const config = rc('myapp', defaults);
app.listen(config.port, () => {
console.log(`Server running on port ${config.port}`);
});
// Bad: Don't load in request handlers
app.get('/api/data', (req, res) => {
const config = rc('myapp', defaults); // Avoid this!
// ...
});