CLI tool
dylang/npm-check avatar
dylang/npm-check

npm-check: one command for outdated, unused and wrong dependencies

Check for outdated, incorrect, and unused dependencies.

6,639 stars233 forksJavaScriptMIT

At a glance

What is it?
A small MIT licensed CLI from dylang that audits a package.json against the registry and your own source, then offers to fix what it finds through an interactive picker.
Who is it for?
npm-check earns its place next to a normal `npm outdated` run because the unused half of the check is the part most projects never do, and depcheck does that work by reading your require and import statements rather than guessing from package.json alone.
Can I use it commercially?
Yes. MIT 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 17 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 September 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Installing the CLI and running it against a project

Installation is a global npm install and the first run takes no arguments, which is the shortest path between a package.json and a list of things wrong with it.

bash
npm install -g npm-check

Then run it from the root of the project:

bash
npm-check

With no path argument the tool checks the current directory, and passing another path checks that instead, which is handy when you keep several packages in one repository. The README is explicit about what the result looks like: a per-package table showing whether a dependency is out of date, whether anything in your code actually imports it, and a link to that package's documentation so you can decide whether the update is worth taking. When everything is current and used, the output is short. When updates are needed the process returns a non-zero exit code, which is the detail that turns this from a console toy into something you can put in a pipeline.

The repository tree is small enough to read in a few seconds: `bin/` for the command entry point, `lib/` for the implementation, `index.d.ts` for the TypeScript definitions, and a `package.json` that declares the `npm-check` binary as `bin/cli.js`. The MIT licence and the `renovate.json` file at the root suggest the maintainer dogfoods automated updating on this project itself.

Reading the flag list instead of guessing at the defaults

The options block in the README is the real documentation for this tool, and it is worth reading once before you trust the defaults.

bash
npm-check <path> <options>
  -u, --update          Interactive update.
  -g, --global          Look at global modules.
  -s, --skip-unused     Skip check for unused packages.
  -p, --production      Skip devDependencies.
  -d, --dev-only        Look at devDependencies only (skip dependencies).

Two of those flags change the meaning of the run rather than trimming its output. `-p` skips anything listed under `devDependencies`, which is what you want in a production image where build tooling is irrelevant. `-d` does the opposite and looks only at development dependencies, which is the useful direction when you are trying to slim a laptop's install or find which linting plugin is dragging a version constraint forward.

The unused check is on by default and can be turned off with `-s`. The README notes it is also skipped automatically in global and update modes, because in both of those cases the tool is looking at the installed tree rather than your own source. Ignoring noise is done with `-i` and a glob, for example `npm-check -i babel-*`, which is the escape hatch for projects with generated or convention driven imports that a static scan cannot see.

Interactive updates route through your own npm install

The `-u` flag turns the report into a picker. You choose which packages to move, and the tool rewrites the versions in package.json. The design decision worth knowing is that npm-check deliberately updates through `npm install` rather than `npm update`, following a recommendation from the npm team, and it always uses the globally installed npm version so that a single directory never ends up with two package managers writing into it.

The installer is not fixed, though. Setting `NPM_CHECK_INSTALLER` switches the underlying command:

bash
NPM_CHECK_INSTALLER=pnpm npm-check -u
## pnpm install --save-dev foo@version --color=always

The commented line in that block is the command npm-check ends up running, which makes the environment variable easy to reason about: whatever you name becomes the installer. The README also suggests `NPM_CHECK_INSTALLER=echo npm-check -u` as a dry run, since `echo` prints the command instead of performing it. That is the safest way to see exactly what a batch of updates would do to your lockfile.

For automation there is `-y`, which applies every update without prompting. The README frames that as the CI-oriented counterpart to `-u`, and paired with the non-zero exit code on pending updates it gives you a build that fails when dependencies drift behind the registry.

What depcheck does for the unused half

The unused detection is not npm-check's own invention. The dependency list in package.json names `depcheck` at `^1.4.7`, and the README points at the depcheck documentation for the `--specials` flag, which controls whether special files such as webpack config or the `scripts` section of package.json are scanned too.

bash
npm-check --specials=bin,webpack

That line matters more than it first looks. A default scan reads `require` calls and `import from` statements in your code, which catches the obvious cases and misses the ones where a package is only referenced by name in a config file or a shell script. The README also calls out support for ES6 style `import from` syntax and for scoped packages, both public and private, which were the two most common false negatives in earlier versions of this kind of tool.

Registry behaviour is handled too. npm-check works with any public npm registry, with private registries such as npm Enterprise, and with alternates like Sinopia, and it does not query the registry at all for any package marked `private: true` in package.json. That last detail is the one to check first if you run this on an internal package, since a registry query for something that is not published will either fail or leak the name.

The Node requirement in package.json is far past what the README says

The README states its requirement as Node 10.9.0 or newer. The package.json in the repository says something much stricter:

json
"engines": {
  "node": ">=24.21.0"
}

Both statements are in the same project at the same revision, and only one of them can describe the code as it currently stands. The dependency list explains why the newer floor exists: chalk `^6.0.0`, meow `^14.1.0`, execa `^10.0.1` and globby `^16.2.4` are all recent major versions that drop older runtimes, and so are inquirer `^14.2.2` and ora `^9.4.1`. The README text has simply not been rewritten to match.

There is a second reason to read that engines block as authoritative. The README says the tool works with `npm@2` and `npm@3` as well as alternative installers like pnpm and ied, which describes an era of the ecosystem, while the release recorded for version 6.0.1 was published on 2022-07-16. The tag list has one entry, so there is no changelog trail to reconcile the two. For a global install on an old machine, trust package.json and not the requirements line.

A documented API for wrapping this in your own tooling

The README does not stop at the command line. There is an API section aimed at people wrapping the check into a CI toolset, and it is short enough to read entirely.

js
const npmCheck = require('npm-check');

npmCheck(options)
  .then(currentState => console.log(currentState.get('packages')));

The function returns a promise resolving to a state object with a `packages` map, and the README documents `update` as the main option, defaulting to false. The fact that `index.d.ts` sits in the root and is wired up through both `types` and `typings` means a TypeScript consumer gets the same surface without writing a declaration by hand.

What is missing from that API section is as informative as what is in it. The README mentions options and then moves on to the command line flags, with no coverage of error shapes, exit code values or how the state object changes after an update. If you are embedding this rather than running it, expect to read the `lib/` directory for those answers.

Editorial conclusion

npm-check earns its place next to a normal `npm outdated` run because the unused half of the check is the part most projects never do, and depcheck does that work by reading your require and import statements rather than guessing from package.json alone. It is a small CLI with an MIT licence, 6639 stars and a single 2022 release in the tag list, last pushed on 2026-09-19, so the risk is not abandonment but drift between what the README promises and what the current package.json installs. Start with a bare `npm-check` inside a project you can afford to have rewritten, read the output before touching a key, and treat the `-u` interactive mode as a review tool rather than a reflex.

Frequently asked questions

How do I find unused dependencies in a Node project?

npm-check checks this by default. It reads your require and import statements to decide whether anything in your code actually pulls a package in, and lists the ones nothing references. The scan can be turned off with `-s`, and extended to config files with `--specials=bin,webpack` when a package is only named in a webpack config or the scripts section of package.json.

Can npm-check update dependencies without asking me each time?

Yes, `-y` applies every update without prompting, which is the flag the README points at for automating dependency updates in CI. Updates go through `npm install` using your globally installed npm, and the process also exits non-zero when updates are pending, so a build can fail on drift. Setting NPM_CHECK_INSTALLER switches the underlying command to pnpm or another installer if you prefer one.

Does npm-check work with private packages and private registries?

The README lists support for scoped packages, npm Enterprise style private registries, and alternates like Sinopia. Any dependency marked `private: true` in package.json is skipped rather than sent to a registry, which keeps unpublished internal packages from failing the check.

Official sources

  1. dylang/npm-check on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dylang-npm-check.svg)](https://hysenlabs.com/projects/dylang-npm-check)