node-config: hierarchical configuration for Node.js deployments
Node.js Application Configuration
At a glance
- What is it?
- node-config layers default.json, environment-specific override files and environment variables into one config object. It is a good fit for multi-environment Node services and a poor fit for edge runtimes with no writable config directory.
- Who is it for?
- Adopt node-config if you run a Node.js service across several named environments and want the environment chosen by NODE_ENV rather than by code. Do not adopt it if you target an edge or serverless runtime where the config directory is not present at build or run time, or if you need a config store that changes without a restart.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 10 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The deployment problem node-config is built around
A Node.js service usually needs different database hosts, timeouts and feature flags in development, qa, staging and production. The naive approach is a single config file plus a chain of if statements on process.env.NODE_ENV. That works until two environments need to share most values and differ in three, at which point the file fills with conditional logic.
node-config takes the opposite approach. The README describes it as organizing "hierarchical configurations for your app deployments": you define a set of default parameters and extend them per environment. The target user is a team shipping the same application binary to several named environments, where the environment is a deployment concern rather than a code concern. The README frames the goal as a consistent configuration interface shared among a growing list of npm modules that also use node-config, which matters if a dependency expects the same config object your app uses.
It is not aimed at single-environment scripts, and it is not a secret manager. The README points to a separate wiki page on securing production config files, which is a hint that file protection is outside the core package.
How the merge order works: default.json, production.json, then the environment
The mechanism is a layered merge keyed on the environment name. Files live in a config directory inside your application. config/default.json supplies base values. A file named after the environment, such as config/production.json, overrides only the keys it declares. The README's own walkthrough makes the result explicit: with NODE_ENV=production, the port and dbName elements of dbConfig come from default.json, while the host element comes from production.json. The merge is per key, not per file, so a production file containing three keys does not discard the rest of the defaults.
The README lists three further override channels on top of the files: environment variables, command line parameters, and external sources such as a database. Each links to its own wiki page, and the README does not restate the precedence rules inline, so the ordering between, say, a command line parameter and an environment variable has to be read from the wiki rather than from the README. That is a real documentation gap for anyone relying on more than one override channel at once.
Access is through a small API. config.get() returns a value and throws for undefined keys, which the README presents as a deliberate choice to catch typos and missing values early. config.has() tests whether a value is defined, which is the intended way to handle optional settings. JSON is the example format throughout the README, but the wiki page on configuration files notes that other file formats are supported; the devDependencies in package.json list parsers for yaml, toml, properties, cson, hjson and x2js, which is consistent with that claim.
There is also a TypeScript story. Type declarations are published under types/ and resolved via typesVersions, with subpath typings for config/parser, config/util/defer and config/lib/util in addition to the main config entrypoint. The package.json confirms this with a types field pointing at types/lib/config.d.ts and a typesVersions map covering those subpaths.
Installing node-config and a first working override
The README's quick start installs the package into your app directory and creates the config folder. The package name on npm is config, which is worth noting because the repository is node-config/node-config. Run this from your project root:
npm install config
mkdir config
vi config/default.jsonThe default file holds the values every environment shares. The README's example nests a database block and a credit block:
{
"Customer": {
"dbConfig": {
"host": "localhost",
"port": 5984,
"dbName": "customers"
},
"credit": {
"initialLimit": 100,
"initialDays": 1
}
}
}The production override declares only what changes. In the README's example that is the host and the credit window:
{
"Customer": {
"dbConfig": {
"host": "prod-db-server"
},
"credit": {
"initialDays": 30
}
}
}In code, config.get() takes a dotted path and returns the merged value. config.has() guards optional settings so a missing key does not throw:
const config = require('config');
const dbConfig = config.get('Customer.dbConfig');
db.connect(dbConfig, ...);
if (config.has('optionalFeature.detail')) {
const detail = config.get('optionalFeature.detail');
}Finally, set the environment before starting the process. With this in place, the README states that port and dbName come from default.json while host comes from production.json:
export NODE_ENV=production
node my-app.jsIf you skip NODE_ENV, the override file for production is never consulted, and the app silently runs on defaults. That is the single most common way this setup goes wrong in a deploy script. The package requires Node >= 20.11.0 according to package.json, so confirm your runtime before installing.
Where node-config stops being the right tool
The config directory is read from the application's filesystem. That assumption breaks in runtimes where the working directory is not what you think it is, or where no config directory is shipped. A bundler that inlines modules can miss the config files unless it is configured otherwise; the README links a dedicated wiki page on webpack usage, which exists precisely because this is a known friction point. If your build step produces a single artifact and the deploy does not copy config/ next to it, config.get() has nothing to read.
Values are loaded at process start. There is no documented mechanism in the README for swapping a value in a running process, so a change to a config file requires a restart. Teams that expect config edits to propagate live will be disappointed, and the README does not document rollback of a bad config change either.
Reserved words are another edge. The README links a wiki page on reserved words, which implies that certain key names collide with the config object's own properties and cannot be used freely as top-level keys. The README does not enumerate them, so you have to check the wiki before naming a top-level section something like get.
Finally, node-config is not a secrets store. Storing credentials in a JSON file that ships with the application is exactly the pattern the wiki page on securing production config files exists to address. If your threat model requires a vault with audit logs and rotation, node-config is the wrong layer.
node-config compared with dotenv and with a remote config service
The closest alternative for many teams is dotenv, which reads a .env file into process.env and stops there. The difference is the shape of the data. dotenv gives you flat string keys, so nested structure has to be encoded in the key name and parsed back by hand. node-config gives you a nested object with per-environment file merging and type preservation, which is why port stays a number in the README example rather than becoming the string "5984". If your configuration is a dozen flat values and one environment, dotenv is less machinery. If you have nested structure and four environments, dotenv pushes the merge logic into your own code.
The other alternative is a remote configuration service, the category the README gestures at with its wiki page on configuring from a DB or external source. The difference in approach is where the source of truth lives. node-config treats files in the repository as the baseline and remote sources as an override layer, so the default deployment works with no network dependency. A remote service inverts that: the process cannot start correctly until it has fetched its configuration, which buys live updates at the cost of a startup dependency and a new failure mode when the service is unreachable. node-config's external source support means you can approximate the remote model without giving up the file baseline, but the README does not describe the failure behaviour when that external source is down.
Maintenance, licence and what an upgrade costs
The repository is not archived, and the last push was on 2026-09-20. Recent releases are v5.0.1 on 2026-08-18, v5.0.0 on 2026-08-03 and v5.0.0-alpha.2 on 2026-06-27, so the 5.x line is recent and the project has shipped a patch after the major. The README also links a page on upgrading from Config 0.x, which tells you the project has carried users across at least one major version boundary, but that page covers 0.x and says nothing about the 4.x to 5.x move.
The runtime dependency list is short: json5, used for parsing. Everything else in package.json sits under devDependencies, including the parsers for yaml, toml, properties, cson, hjson and x2js. That is a meaningful upgrade consideration: if you rely on one of those non-JSON formats, the parser is not a runtime dependency of the package, so you supply it yourself. The README's own quick start stays in JSON for that reason.
On licence, package.json declares "license": "MIT", while the repository metadata carries a NOASSERTION identifier, meaning the automated classifier did not match a known licence. The LICENSE file is present at the top level. Read it rather than trusting either label, and note that the author field is a single named individual, which is worth knowing when you assess how the project is sustained. Nothing here is legal advice.
The engines field requires Node >= 20.11.0. An upgrade from an older Node runtime is therefore a prerequisite for the 5.x line, and that constraint will hit you before any config API change does.
Editorial conclusion
Adopt node-config if you run a Node.js service across several named environments and want the environment chosen by NODE_ENV rather than by code. Do not adopt it if you target an edge or serverless runtime where the config directory is not present at build or run time, or if you need a config store that changes without a restart. Before committing, verify that your deploy pipeline ships the config/ directory alongside the compiled output, that NODE_ENV is set explicitly, and that your reserved-word collisions are checked. The package requires Node >= 20.11.0, so check that first.
Frequently asked questions
How do I install node-config in a Node.js project?
Run npm install config in your app directory, then create a config folder and a default.json file inside it. The README's quick start shows exactly that sequence, followed by editing a per-environment override file such as config/production.json.
Where is the node-config config file located?
Configuration files live in a config directory inside your application, not in a global location. The README creates it with mkdir config and puts default.json and environment files such as production.json there.
Is there a node-config alternative for simpler setups?
dotenv is the common alternative: it loads a .env file into process.env as flat strings, with no nested merging and no per-environment file layering. node-config instead merges default.json with an environment-specific file and preserves value types.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/node-config-node-config)