configstore: per package JSON settings in the XDG config directory
Easily load and persist config without having to think about where and how
At a glance
- What is it?
- configstore is a small Node package that persists settings as one JSON file per application in the XDG config directory, with dot notation keys, atomic writes and an API of eight methods. The judgement is that it does exactly one thing cleanly, and that its own README points you to a newer package for most new projects.
- Who is it for?
- configstore suits a small CLI or build tool that needs to remember a token, a path or a flag between runs and has no interest in a settings UI, and its per application file layout means two tools never fight over the same file. It is the wrong choice for a new project, because the README itself describes conf as a more modern version of configstore, and it is a poor fit for an Electron app, where the README points at electron-store instead.
- Can I use it commercially?
- Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 90 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 October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One JSON file per application
The idea is small enough to state in one sentence, and the README states it as easily load and persist config without having to think about where and how. The config is stored in a JSON file located in $XDG_CONFIG_HOME or ~/.config, with the example path given as ~/.config/configstore/some-id.json. The identifier is the package name, passed to the constructor, so every application that uses the library gets its own file and cannot corrupt another tool's settings. The dependency list explains the behaviour more precisely than the prose does. xdg-basedir resolves the platform directories, dot-prop provides the dot notation, atomically provides atomic writes, graceful-fs handles the file system calls, and is-safe-filename validates the identifier before it becomes a path. That last one is the sort of detail that matters for a library whose whole purpose is turning a string into a filesystem path, and it is the kind of thing you only notice when it is absent.
Installing and first use
The install is a single npm command, and the package is ESM only, with type set to module and exports pointing at index.js:
npm install configstoreThe usage example in the README reads the package name out of package.json, creates an instance with an identifier and a defaults object, and then shows the shape of the API in a few lines:
import fs from 'node:fs';
import Configstore from 'configstore';
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
// Create a Configstore instance.
const config = new Configstore(packageJson.name, {foo: 'bar'});
console.log(config.get('foo'));
//=> 'bar'What you should see is that the defaults object is populated on the first read, before the user has configured anything, which is what makes a settings file usable by a tool that has to run with no configuration at all.
Eight methods and two behaviours to know
The API is deliberately small. There is set(key, value) and set(object) to write one item or many, get(key) and has(key) to read, delete(key) and clear() to remove one item or everything, size for the item count, and path for the location of the config file, which the README says can be used to show the user where the file is or even open it for them. The all property is both a getter and a setter, returning the whole config as an object or replacing it with one. Two behaviours matter in practice. Keys accept dot notation, so config.set('bar.baz', true) creates a nested object and config.get('bar') returns it. And a missing key does not throw or return a sentinel, it returns undefined, which is why the README recommends the nullish coalescing operator to supply defaults, with config.get('nonexistent') ?? 'default value' as the example. For a library that stores user settings, the dot notation and the undefined default together are the API you will actually use every day.
Three options, two of which the README discourages
The constructor takes an options object, and the three settings in it exist for specific situations, two of which the documentation tells you to think hard about. globalConfigPath, defaulting to false, stores the config at $CONFIG/package-name/config.json instead of the default $CONFIG/configstore/package-name.json, and the README says this is not recommended since you might end up conflicting with other tools, which renders the whole without having to think idea moot. configPath, defaulting to automatic, sets the path of the config file directly and overrides both the id and globalConfigPath options, and the wording is a warning, please do not use this option unless absolutely necessary and you know what you are doing. The third option is the useful one. clearInvalidConfig defaults to true, and it controls what happens when the file contains invalid JSON: with the default the file is cleared, and with it set to false a SyntaxError is thrown instead so you can recover the corrupted file manually. The third behaviour is the sane default for a tool that a user runs unattended, and the escape hatch is there for when you want to see the broken file before it disappears.
The README points you to two other packages
Two lines at the top of the README are the most useful guidance in the file. If you need this for Electron, the text says to check out electron-store instead, and it also points to conf as a more modern version of configstore. That is the alternative worth discussing, because it is the same author's line of work rather than an unrelated competitor, and the difference in approach is generational. configstore is a JSON file per package in the XDG config directory, written with atomic writes, and it is the older of the two. The newer package is the one the author would pick for a new project, and the fact that configstore is still at version 8.0.0 with a BSD-2-Clause licence and an active commit history in July 2026 means both are maintained, so the choice is about which generation of the design you want rather than about abandonment. The README does not spell out the internals of the alternatives, so if you are choosing between them, read their own documentation rather than inferring it from this one.
A package small enough to read in full
The repository is unusually small, and that is an argument in its favour. The top level holds an editorconfig, a gitattributes file, GitHub configuration, an npmrc, index.d.ts, index.js, a license file, package.json, readme.md and test.js, and the published files array in the manifest contains only index.js and index.d.ts. There is no build step in the scripts, only a test command that runs xo and then ava, with ava configured to run serially, which suggests the tests share a config file on disk and therefore cannot run in parallel. The manifest declares engines node >= 20, marks the package as side effect free, and points types at index.d.ts, so it ships with TypeScript definitions and a clean tree shaking story. The package is funded through the author's sponsorship page, and the manifest lists the funding URL, which is how maintenance of a library this small gets paid for.
Versioning tells you how much churn to expect
The release history is the last thing to weigh. The tags are v7.0.0 from 2024-07-13, v7.1.0 from 2025-09-15 and v8.0.0 from 2026-01-24, so the package has moved through major versions on a scale of roughly a year to two, and the last push to the branch was on 2026-07-25 with the repository not archived. A major bump in a library with this small an API usually means a change in the Node baseline or in the module format rather than a redesign, and the current manifest already pins node >= 20 and the ESM only exports field, which is the sort of change that would explain a version 8. The practical advice for an adopter is to read the release notes for the major version you are moving to before upgrading a tool that stores user data, since a change in where the file lives or in how it is written is exactly the kind of thing that would need a migration. The licence is BSD-2-Clause, which is permissive and carries no obligation on the projects that use it.
Editorial conclusion
configstore suits a small CLI or build tool that needs to remember a token, a path or a flag between runs and has no interest in a settings UI, and its per application file layout means two tools never fight over the same file. It is the wrong choice for a new project, because the README itself describes conf as a more modern version of configstore, and it is a poor fit for an Electron app, where the README points at electron-store instead. Before you adopt it, check that the XDG config directory is writable in the environment where your tool runs, since that assumption breaks on locked down machines and in some container images, and decide whether a single JSON file per package is the storage shape your users will be able to find and repair by hand.
Frequently asked questions
Where does configstore store the config file?
The config is stored as a JSON file in $XDG_CONFIG_HOME or ~/.config, with the example path given as ~/.config/configstore/some-id.json, where the identifier is usually the package name. The path property returns the location of the file so a tool can show it to the user.
What happens if the config file contains invalid JSON?
By default, clearInvalidConfig is true and the config file is cleared. If you set it to false, a SyntaxError is thrown instead of clearing the file, which lets you recover a corrupted config manually.
Should I use configstore or conf for a new project?
The README points to conf as a more modern version of configstore, and to electron-store if the target is an Electron app. configstore itself is at version 8.0.0, requires Node 20 or newer, and is still being worked on, with the last push on 2026-07-25.
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/sindresorhus-configstore)Was this useful?