What is cosmiconfig?
The cosmiconfig npm package is a utility for finding and loading configuration from a variety of file formats and locations. It is commonly used in Node.js projects to create flexible configuration systems for tools and libraries.
What are cosmiconfig's main functionalities?
Searching for configuration files
This feature allows you to search for configuration files with a given name in various locations, including package.json properties, rc files, and regular JSON or YAML files.
const cosmiconfig = require('cosmiconfig');
const explorer = cosmiconfig('yourModuleName');
explorer.search()
.then((result) => {
const config = result ? result.config : {};
// do something with config
})
.catch((error) => {
// handle error
});
Loading configuration files directly
This feature allows you to load a configuration file directly from a specified path, regardless of the file's format.
const cosmiconfig = require('cosmiconfig');
const explorer = cosmiconfig('yourModuleName');
explorer.load('/path/to/config').then((result) => {
const config = result ? result.config : {};
// do something with config
}).catch((error) => {
// handle error
});
Creating a custom explorer
This feature allows you to create a custom explorer with specific search places and loaders, enabling you to define where and how configuration files should be found and interpreted.
const cosmiconfig = require('cosmiconfig');
const explorer = cosmiconfig('yourModuleName', {
searchPlaces: ['custom.config.js', 'package.json'],
loaders: {
'.js': cosmiconfig.loadJs,
'.json': cosmiconfig.loadJson
}
});
Other packages similar to cosmiconfig
rc
The 'rc' package is similar to cosmiconfig in that it also searches for and loads configuration files. However, 'rc' focuses on a specific pattern of '.rc' files and does not support as many file formats as cosmiconfig.
config
The 'config' package is another configuration loader that supports multiple file formats. Unlike cosmiconfig, 'config' is designed for application configuration and has a different approach to file discovery, defaulting to a 'config' directory.
convict
Convict is a configuration management library that includes schema definitions. It is more opinionated than cosmiconfig and includes validation and environment variable support out of the box, which cosmiconfig does not do without additional setup.
cosmiconfig
Find and load a configuration object from a package.json
property, JSON or YAML "rc file", or .config.js
CommonJS module.
For example, if your module's name is "soursocks," cosmiconfig will search out configuration in the following places:
- a
soursocks
property in package.json
; - a
.soursocksrc
file in JSON or YAML format; - a
soursocks.config.js
file exporting a JS object.
cosmiconfig continues to search in these places all the way down the file tree until it finds acceptable configuration or hits the home directory. And it does all this asynchronously, so it shouldn't get in your way.
Last but not least: cosmiconfig contains built-in support for extends
functionality — so your module can provide shareable configs with no extra effort on your part (!).
API
var cosmiconfig = require('cosmiconfig');
cosmiconfig(yourModuleName[, options])
.then(function(result) {
})
.catch(function(parsingError) {
});
The function cosmiconfig()
searches for configuration objects and returns a Promise;
and that Promise resolves with an object containing the information you're looking for.
So let's say yourModuleName = 'goldengrahams'
— here's how cosmiconfig will work:
- Starting from
process.cwd()
(or some other directory defined by options.cwd
), it looks for configuration objects in three places, in this order:
- A
goldengrahams
property in a package.json
file (or some other property defined by options.packageProp
); - A
.goldengrahamsrc
file with JSON or YAML syntax (or some other filename defined by options.rcName
); - A
goldengrahams.config.js
JS file exporting the object (or some other filename defined by options.jsName
).
- If none of those searches reveal a configuration object, it moves down one directory and tries again. So the search continues in
./
, ../
, ../../
, ../../../
, etc., checking those three locations in each directory. - It continues searching until it arrives at your user directory (or some other directory defined by
options.stopDir
). - If at any point a parseable configuration is found, the
cosmiconfig()
Promise resolves with its result object. - If no configuration object is found, the
cosmiconfig()
Promise resolves with null
. - If a configuration object is found but is malformed (causing a parsing error), the
cosmiconfig()
Promise rejects and shares that error (so you should .catch()
it).
cosmiconfig(moduleName[, options])
Returns a promise that resolves with null
(if no configuration was found) or an object with the following properties:
- config: The parsed configuration object that was found.
- filepath: The path to the file that housed that configuration object.
moduleName
Type: string
You module name. This is used to create the filenames that cosmiconfig will look for.
Options
cwd
Type: string
Default: process.cwd()
Directory to start the search from.
rcName
Type: string
Default: '.[moduleName]rc'
Name of the "rc file" to look for, which can be formatted as JSON or YAML.
jsName
Type: string
Default: '[moduleName].config.js'
Name of a JS file to look for, which must export the configuration object.
stopDir
Type: string
Default: Absolute path to your home directory
Path which the search will stop.
allowExtends
Type: Boolean
Default: false
If true
, allow configuration objects to extend other configuration objects via the extends
property. See below.
Extends
If you set options.allowExtends = true
, configuration objects will be able to explicity extend other configuration objects. This opens the door to shareable configs, in the manner of ESLint and stylelint.
Configurations can contain an extends
value that is a single string or an array of strings. Each string must be a lookup that require()
will understand from the context of the that file, so one of the following:
- an npm module name;
- an absolute path;
- a relative path, relative to the configuration file that is contains the
extends
.
When one config extends another, it merges its own properties into the other's. For example, if Config A extends Config B, the result that cosmiconfig returns is Config A's properties merged into Config B (so Config A's take priority).
You can extend multiple configs, and extended configs can extend other configs. So if you load Config A, which extends Config B and Config C, and Config C extends Config D — the resultant configuration object be the merging of all, A, B, C, and D. Wowza.
Differences from rc
rc serves its focused purpose well. cosmiconfig differs in a few key ways — making it more useful for some projects, less useful for others:
- Looks for configuration in some different places: in a
package.json
property, an rc file, and a .config.js
file. - Built-in support for JSON, YAML, and CommonJS formats.
- Stops at the first configuration found, instead of finding all that can be found down the filetree and merging them automatically.
- Provides a few configuration options (e.g. different file name expectations).
- Provides
extends
support. - Asynchronicity.