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

local-npm-registry

v1.0.0

Published

Manages local npm package installations and updates across your machine.

Readme

local-npm-registry

JSR NPM License

🚀 Supercharge your local development workflow! This CLI tool manages local npm package installations as if they were published, making it effortless to test changes across multiple projects without the hassle of publishing to npm or linking packages manually.

📦 Installation

Install as a dev dependency in both your library and consuming projects:

npm install -D local-npm-registry
# or
pnpm add -D local-npm-registry

🎯 Quick Start

1. Set up your library project for development

In your library project (the one you want to test changes from), set up a watch command using nodemon:

{
  "scripts": {
    "dev": "nodemon --ignore lib/ -e ts --exec \"npm run build && local-npm publish\""
  }
}

💡 Pro tip: You can pass any npm publish options to local-npm publish. For example, use local-npm publish --ignore-scripts if you want to skip pre/post-publish scripts.

Now when you run npm run dev, every time you save a TypeScript file, your library will rebuild and automatically update all consuming projects!

2. Subscribe your frontend project to the library

In your frontend/consuming project, first install the tool as a dev dependency, then add a convenient script:

{
  "scripts": {
    "sub:my-library": "local-npm subscribe @my-org/my-library",
    "unsub:my-library": "local-npm unsubscribe @my-org/my-library"
  }
}

Then subscribe to your library:

cd my-frontend-project
npm run sub:my-library

That's it! Your frontend project will now automatically receive updates whenever you make changes to your library.

🛠️ Core Commands

local-npm publish [npm-publish-options]

📤 Publishes your current package and automatically updates all projects that are subscribed to it.

  • Creates a version carrying the publishing directory and the moment it was published (e.g., 1.2.3-pa1b2c3d4.20250528123456789)
  • Updates all subscriber projects with the new version
  • Perfect for the watch command in your library
  • Supports all npm publish options: Pass any npm publish options directly to the underlying npm publish command
# Basic publish
local-npm publish

# Publish without running scripts
local-npm publish --ignore-scripts

# Publish with verbose output for debugging
local-npm publish --verbose

local-npm subscribe <package-name> [--path <path>]

🔔 Subscribe to a package to receive automatic updates when it's published locally.

  • Adds your current project as a subscriber
  • Installs the latest local version immediately
  • Preserves publish arguments: Uses the same npm publish options as the package's most recent publish
  • Use --path to pick which directory to subscribe to when a package is published from several
  • Great for frontend projects consuming your libraries

local-npm unpublish [package-name] [--path <path>] [--all-paths]

🗑️ Removes a package from the local registry and resets all subscribers to original versions.

  • Cleans up when you're done testing
  • Resets all subscribers back to their original package versions
  • Removes only what the target directory published, leaving other directories alone
  • Defaults to the current directory, or to the only one publishing the package. Use --path to pick one of several, or --all-paths for every one

local-npm unsubscribe [package-name]

🔕 Unsubscribe from packages and reset to original versions.

  • Remove subscription from one package or all packages (if no name provided)
  • Resets your project back to the original package versions
  • Leaves any subscriptions you keep working as they were

💡 Why Use This?

No more npm link headaches - Works reliably across different package managers
Automatic updates - Changes propagate instantly to all consuming projects
Clean workflow - Easy to set up and tear down
Version safety - Always keeps track of original versions to restore
Multiple subscribers - One library can update many consuming projects at once
True package installation behavior - Unlike local file paths, this tool installs packages the same way as remote registries, ensuring your local testing matches production behavior

🔧 Additional Commands

  • local-npm prune - Drop packages whose publishing directory is gone and reset their subscribers.
  • local-npm list - See all packages in your local registry and their subscribers
  • local-npm get-store - View the raw local package store data
  • local-npm config - Show current configuration
  • local-npm init-config - Create a configuration file
  • local-npm clear-store - Reset everything and start fresh, emptying the registry's storage

⚙️ Configuration

The tool can be configured using a .local-npm-registry.json file. The configuration file is searched starting from the current working directory and traversing up the directory tree until found.

{
  "dataDirectory": "/path/to/data",
  "registryPort": 4873,
  "registryUrl": "http://localhost:4873",
  "verdaccioConfig": {}
}
  • dataDirectory (string, optional): The base directory where all local-npm-registry data should be stored. If not specified, defaults to the user's home directory. A .local-npm-registry subdirectory will be created within this directory.

  • registryPort (number, optional): The port number for the local Verdaccio registry server. Defaults to 4873.

  • registryUrl (string, optional): The full URL of the local Verdaccio registry. Defaults to http://localhost:4873.

  • verdaccioConfig (object, optional): Custom Verdaccio configuration that will override the default settings. This allows you to customize the registry behavior beyond the basic options.

You can create a default configuration file in your project using:

local-npm init-config

This will create a .local-npm-registry.json file in the current directory with default values that you can then customize.

📋 Technical Details

How It Works

This tool uses Verdaccio (a private npm registry) under the hood to simulate publishing packages locally. It maintains a JSON store that tracks package versions and subscriber relationships, ensuring clean workflows and easy cleanup.

Each publishing directory keeps exactly one version in the registry: publishing again replaces what that directory published last and leaves every other directory's version alone.

Note: Verdaccio is started and stopped for you. Any command that publishes or installs runs it, since local versions resolve nowhere else.

To see more in depth information on the logic and specifics, see Scenarios which works through behavior one case at a time, from a single library and consumer up to two checkouts of one monorepo publishing at once (e.g. git worktrees).

Why Not Use Local File Paths?

While npm supports local file paths as dependencies (e.g., "my-package": "file:../my-package"), this approach has significant limitations:

  • Different installation behavior: Local paths don't install the package the same way as remote registries do
  • Missing dependency resolution: The local package's own dependencies aren't automatically installed in the consuming project
  • No build processes: Pre-publish scripts and build steps are often skipped
  • Inconsistent testing: Your local testing environment differs from how the package will actually be consumed in production

This tool solves these issues by using a real npm registry (Verdaccio) locally, ensuring that packages are installed, built, and resolved exactly as they would be when published to the public npm registry.

Local JSON Store Structure

Every package is keyed by its name, then by the absolute path of the directory it is published from, so two copies of one repository each get their own entry.

Published versions take the form <yourVersion>-<pathSlug>.<timestamp>. The slug is derived from the publishing directory's path, which a version cannot hold whole, and it is what keeps two publishing directories of one package from landing on the same version. You never have to type it: every command takes a path.

{
  "version": 2,
  "packages": {
    "@aneuhold/core-ts-lib": {
      "/path/to/core-ts-lib": {
        "originalVersion": "1.2.3",
        "currentVersion": "1.2.3-pa1b2c3d4.20250526123456789",
        "subscribers": [
          {
            "subscriberPath": "/path/to/subscriber-project-1",
            "originalSpecifier": "^1.2.3"
          },
          {
            "subscriberPath": "/path/to/subscriber-project-2",
            "originalSpecifier": "~1.2.0"
          }
        ],
        "publishArgs": ["--ignore-scripts", "--verbose"]
      }
    },
    "@aneuhold/be-ts-lib": {
      "/path/to/be-ts-lib": {
        "originalVersion": "2.1.0",
        "currentVersion": "2.1.0-pf9e8d7c6.20250526134567890",
        "subscribers": [
          {
            "subscriberPath": "/path/to/subscriber-project-3",
            "originalSpecifier": "^2.1.0"
          }
        ]
      }
    }
  }
}