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

lockbisect

v0.1.0

Published

git bisect for the inside of a lockfile diff. When a batch dependency update breaks CI, isolate the exact culprit package@version in O(log n) installs.

Readme

lockbisect

git bisect for the inside of a lockfile diff.

A grouped dependency update bumped a pile of packages in one commit and CI went red. git bisect is useless — it was one commit. lockbisect finds the exact culprit package anyway.

npm node deps license


Dependabot, Renovate, and npm update all do the same brutal thing: they change dozens of packages in a single commit. When that commit breaks your build, git bisect can only narrow it down to... that one commit. You're left to find the culprit by hand — splitting the package-lock.json diff into synthetic commits, or reverting packages one at a time. It's an afternoon of work for a question a machine can answer in a handful of installs.

lockbisect is that machine. Point it at the last-good and first-bad commits plus your test command, and it binary-searches the changed packages — reinstalling the good lockfile with subsets forced to their bad versions — until it names the one that broke you.

npx lockbisect --good HEAD~1 --test "npm test"
lockbisect v0.1.0
HEAD~1@d70a7ba (good) → HEAD@a45b670 (bad) · package-lock.json
11 changed packages to search:
  · ansi-regex 6.0.0 → 6.1.0
  · ansi-styles 6.0.0 → 6.2.1
  · chalk 5.0.0 → 5.3.0
  … and 8 more

Verifying endpoints…
  #1 testing 11/11 bad-pinned → fail
  #2 testing 0/11 bad-pinned → pass

Bisecting…
  #3 testing 5/11 bad-pinned → pass
  #4 testing 6/11 bad-pinned → fail
  #5 testing 3/11 bad-pinned → pass
  #6 testing 3/11 bad-pinned → fail
  #7 testing 1/11 bad-pinned → fail

✓ Culprit:
  chalk 5.0.0 → 5.3.0
Isolated in 7 installs (a linear sweep would take 11).

Pin the good version to unblock CI (package.json "overrides"):
  "overrides": { "chalk": "5.0.0" }

(Real run — the win grows with the number of changed packages: the search is logarithmic, a manual sweep is linear, and either way it's unattended instead of an afternoon of splitting lockfile hunks by hand.)

Install

npx lockbisect --good <ref> --test "<command>"     # no install needed
# or
npm install -g lockbisect

Zero dependencies. Node ≥ 18. npm lockfiles (lockfileVersion 2 or 3).

Usage

You need three things: a commit where the build was green, a commit where it's red, and a command that tells the two apart.

# The most common case: CI broke on HEAD after a grouped bump.
lockbisect --good HEAD~1 --test "npm test"

# Be specific about what "broken" means — any command, any exit code.
lockbisect --good v2.3.0 --bad v2.3.1 --test "npm run build && node smoke.js"

# A monorepo package, a custom lockfile path, a yarn-style test:
lockbisect --good HEAD~1 --lockfile packages/api/package-lock.json --test "npm -w api test"

| Flag | | | --- | --- | | -g, --good <ref> | Git ref whose lockfile passes (required). | | -t, --test "<cmd>" | Command that exits 0 when healthy, non-zero when broken (required). | | -b, --bad <ref> | Git ref whose lockfile fails. Default: HEAD. | | -l, --lockfile <path> | Lockfile to search. Default: package-lock.json. | | --ignore-scripts | Faster installs; skips postinstall-script breakage. | | --install-timeout <s> / --test-timeout <s> | Per-step caps. Default: 600s. |

The exit code is 0 when a culprit is found, 2 on a usage or setup error.

How it works

The packages whose resolved version changed between the good and bad lockfiles are the search space. lockbisect runs a delta-debugging search over them. To test "is the culprit in this subset?", it:

  1. restores the good lockfile as the base,
  2. forces the subset to their bad versions — direct dependencies pinned in package.json, transitive ones via npm overrides,
  3. runs npm install (npm reconciles a fully consistent tree — so there is no such thing as an un-installable midpoint), then runs your test.

Because every hybrid installs cleanly, the search is O(log n) in the number of changed packages, not O(n). It even handles the nasty case where two packages only break in combination — delta debugging returns the minimal breaking set, not a single wrong answer.

Everything happens in a throwaway git worktree at the bad commit. Your working tree, lockfile, and node_modules are never touched.

Why nothing else does this

| Tool | What it does | Why it's not this | | --- | --- | --- | | git bisect | Bisects commits | A grouped bump is one commit — zero resolution. | | npm-check-updates --doctor | Re-tests upgrades one by one | O(n), forward-only, direct deps only — can't see the transitive bump that broke you, and can't start from the commit you already have. | | npm-bisect | Bisects by registry publish date | Unmaintained ~7 years; date ≠ your lockfile. | | pnpm-update-bisect | Bisects an update set | Dormant prototype, pnpm-only, forward-direction. | | single-package version bisectors | Drill one package's versions | Require you to already know which package broke. |

lockbisect is the only tool that takes a retrospective lockfile diff as its search space. Both Dependabot and Renovate have years-old open feature requests for exactly this, with "ungroup it and retest by hand" as the official answer. This is the automation.

Scope (v1)

  • npm package-lock.json (v2/v3). pnpm and yarn are on the roadmap — nothing good exists there either.
  • Best on dependency-only commits (Dependabot, Renovate, npm update) where the breakage is in a bumped package. If a commit also rewrote package.json ranges and source code, bisect the source with git bisect first.
  • If a midpoint genuinely can't install, it's skipped (like git bisect skip) and the search continues.

Contributing

Bug reports with a real broken lockfile pair are gold — they become test fixtures. pnpm/yarn support and a GitHub Action are the most-wanted additions. See CONTRIBUTING.md. MIT licensed.