npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mahelbir/settings

v5.0.0

Published

Lightweight JSON configuration file loader with deep get/set support and auto-refresh capability.

Readme

node-settings

npm version license

Lightweight JSON configuration file loader with deep get/set support and auto-refresh capability.

Installation

npm i @mahelbir/settings

Ships dual ESM and CommonJS builds — import it whichever way your project uses:

import {Settings} from "@mahelbir/settings";           // ESM
const {Settings} = require("@mahelbir/settings");  // CommonJS

Usage

Instance Mode

Create a Settings instance to read and manipulate a specific JSON file.

import {Settings} from "@mahelbir/settings";

const config = new Settings("./config.json");

config.get("app.name");                  // Deep get
config.get("app.debug", false);          // With default value
config.set("app.version", "2.0.0");      // Replace the value at a key
config.delete("app.deprecated");         // Remove a key
config.save();                           // Write in-memory state to file

Reads and writes hit the in-memory copy; save() is what reaches the file. The full method list is in the API table.

Auto-Refresh (Polling)

Keep an instance in sync with the file on disk. Ideal for long-running processes where config may be updated externally. Polling re-reads the file on an interval; a failed read keeps the last good data.

import {Settings} from "@mahelbir/settings";

const config = new Settings("./config.json");
config.startPolling(5);                  // re-read every 5s (default: 1s)

config.get("feature.enabled");           // always reflects the latest successful read

config.stopPolling();                    // stop refreshing when you're done

Share a single polling instance across your app by exporting it from a module — Node's module cache makes it a singleton (CommonJS require works the same):

// config.js
import {Settings} from "@mahelbir/settings";

const config = new Settings("./config.json");
config.startPolling(5);
export default config;

// anywhere else
import config from "./config.js";

config.get("feature.enabled");

The polling timer keeps the process alive. Call stopPolling() to let the process exit.

Write-Through (put / patch)

put and patch skip the in-memory copy: they read the current on-disk content fresh, apply params, and write atomically under a cross-process lock — so two processes writing different keys don't overwrite each other. A missing or corrupt file is treated as an empty object. What they write surfaces in memory on the next reload() or poll tick.

Replace vs merge

// config.json = {"app": {"name": "demo", "version": "1.0"}}
config.put({app: {version: "2.0"}});     // {"app": {"version": "2.0"}}
config.patch({app: {version: "2.0"}});   // {"app": {"name": "demo", "version": "2.0"}}

| Method | Target | Object value at an existing key | |----------------------------|--------------|---------------------------------| | set("job", {count: 9}) | in-memory | replaces the subtree | | merge("job", {count: 9}) | in-memory | merges into the subtree | | put({job: {count: 9}}) | file (fresh) | replaces the subtree | | patch({job: {count: 9}}) | file (fresh) | merges into the subtree |

merge and patch deep-merge plain objects and replace everything else — arrays, null, primitives and class instances. Keys can be dot paths; at a leaf there is nothing to merge, so each pair agrees there and they differ only on plain object values.

API

All methods below the constructor work on the in-memory copy, except put and patch, which go straight to the file.

| Method | Description | |----------------------------------|-------------------------------------------------------------------------------| | new Settings(file) | Create instance and read from file (required) | | get(key, default?) | Get value by dot-notation key | | has(key) | Whether the key exists; a stored undefined counts as present | | set(key, value) | Replace the value at a key | | merge(key, value) | Deep-merge into the value at a key | | delete(key) | Remove a key | | clear() | Empty all settings | | save() | Write current in-memory state to file | | reload() | Re-read the file now; true on success, false on failure (keeps last good) | | put(params) | Replace the value at each key, straight in the file (fresh read, atomic) | | patch(params) | Deep-merge into the value at each key, straight in the file (fresh read, atomic) | | startPolling(intervalSeconds?) | Start auto-refreshing the instance on an interval (default: 1s) | | stopPolling() | Stop auto-refreshing | | raw() | Return raw internal settings object (mutable reference) | | all() | Return flat key-value map with dot-notation keys | | version() | SHA-1 checksum of the current in-memory data | | fileChecksum() | SHA-1 of the file's bytes on disk right now; null if unreadable |

Upgrading

Coming from v4? See migration guide.

Support

If this project helps you, please consider giving it a Star ⭐️ on GitHub. This will encourage us to continue developing and maintaining this project.