config
Hierarchical configuration management for Node.js apps, with environment-specific overrides and multi-format file support.
Repository Health
Technical Analysis
node-config lets Node.js applications define a set of default configuration parameters and extend them for different deployment environments — development, qa, staging, production — without branching application code on NODE_ENV. Configuration files live in a config/ directory as JSON, YAML, TOML, CSON, HJSON, XML, JS, TS, or .properties files, and are deep-merged in a predictable precedence order: defaults, environment-specific overrides, instance overrides, environment variables, and command-line parameters.
Configuration values are accessed through config.get() and config.has(), which throw on undefined keys instead of silently returning undefined — catching typos and missing values at the point of use rather than deep inside application logic. After the first get() call, the config object is made immutable by default so runtime code can’t accidentally mutate shared configuration state. The library has been in active use since 2010 and is a dependency of a large number of other npm modules that rely on its shared configuration convention.
What You Get
- Deep-merged hierarchical config across default, environment-specific, local, and instance-override files
- Support for JSON, YAML, TOML, CSON, HJSON, XML, JS, TS, and .properties config formats via a pluggable, lazily-loaded parser
- Environment variable and command-line override support, including mapping arbitrary env vars onto config paths via custom-environment-variables files
- A runtime config object with get()/has() methods that is immutable by default after first access
- Published TypeScript type declarations for the main entrypoint and its parser/util subpaths
Common Use Cases
- Separating a production database host or credentials from local development defaults without branching code on NODE_ENV
- Giving each library or sub-module its own default config namespace via config.util.setModuleDefaults()
- Overriding config per deployment instance (e.g. per container) with local.json or instance-suffixed files kept out of version control
- Mapping infrastructure-provided environment variables (e.g. secrets injected by an orchestrator) onto structured config paths via custom-environment-variables.json
- Guarding optional integrations behind config.has() checks so a feature is skipped rather than throwing in environments where it isn’t configured
Under The Hood
Architecture
node-config separates concerns across a small set of classes in lib/util.js and lib/config.mjs: Env abstracts process.env/argv access for testability, Load orchestrates config-directory scanning, file discovery, and NODE_CONFIG/command-line overrides, RawConfig wraps raw file content for lazy custom-format resolution, and ConfigClass is the public-facing object that deep-extends itself with the merged result and exposes get()/has(). The module’s default export is an IIFE at the bottom of config.mjs that runs Load.fromEnvironment(), layers in NODE_CONFIG env/CLI overrides via an internal _init(), and constructs a single ConfigClass instance — so the entire hierarchy-merge pipeline runs once at first require('config'), producing a long-lived singleton that later becomes immutable after its first get() call.
Tech Stack
The package ships a CommonJS shim (lib/config.js) that re-exports a native ESM module (lib/config.mjs), keeping a single implementation for both module systems. Its only runtime dependency is json5, since every other supported config format (YAML, TOML, CSON, HJSON, XML, CoffeeScript, ts-node) is lazy-required from parser.js only when a matching file extension is actually present, keeping the install footprint small for consumers who only use JSON. Type declarations are generated from JSDoc via tsc and validated with @arethetypeswrong/cli, and CI runs the test suite across Node 22.x and 24.x on GitHub Actions alongside a dedicated benchmarks job.
Code Quality
The test suite spans 19 files with roughly 400 individual test cases, run with Node’s built-in test runner and measured with c8 coverage rather than a third-party framework. Error handling is explicit and intentional rather than swallowed: get() throws on undefined or missing keys, and a strictness-check pass in the constructor can warn or throw (via NODE_CONFIG_STRICT_MODE) when NODE_ENV or NODE_APP_INSTANCE values don’t match any config file. Source files carry extensive JSDoc typedefs and doc comments — over half the lines in the core config module are documentation — despite the implementation itself being plain JavaScript rather than TypeScript.
API Design
The library’s central ergonomic choice is making get() fail fast on undefined configuration instead of returning undefined silently, paired with has() for cases where a missing key is expected; this pushes configuration bugs to the call site instead of downstream. Per-module default namespacing (config.util.setModuleDefaults()) lets a dependency register its own defaults without an app owner needing to pre-populate every key a library might read, and config.util.getConfigSources() gives visibility into which files contributed which values — useful when debugging a deeply layered override chain across many config files.
Used by 3 apps in this directory
overleaf
Collaboration · Productivity
Open-source, real-time collaborative LaTeX editor with sandboxed compilation and full TeXLive support for self-hosted academic and research teams.
PeerTube
Social Media
A federated, ActivityPub-based video hosting platform built by Framasoft — self-hostable instances interconnect into a network with no vendor lock-in, P2P-assisted streaming, and no ads.
Trieve
AI Development · Search · Developer Tools
All-in-one self-hostable platform for hybrid search, RAG, recommendations, and analytics built on Rust and Qdrant.