Back

Smarter Package Updates With npm-check-updates

Smarter Package Updates With npm-check-updates

Dependency drift kills projects slowly. You skip a few updates, then a few more, and suddenly you’re staring at 47 outdated packages—half with breaking changes, some with security vulnerabilities, and no clear path forward. Running npm update feels like Russian roulette. Mass upgrades break CI. The safe choice becomes doing nothing, which isn’t safe at all.

npm-check-updates (ncu) offers a different approach: separating the decision of what to update from the act of installing and testing. This distinction matters more than most teams realize.

Key Takeaways

  • ncu modifies package.json version ranges without touching node_modules or your lockfile, giving you control over when installation happens
  • Use --target minor or --target patch to limit updates to non-breaking changes
  • The --peer flag prevents suggesting updates that would cause peer dependency conflicts
  • Always commit package.json and package-lock.json together after testing updates
  • Use npm’s overrides field to force specific versions of transitive dependencies when addressing vulnerabilities

Why Blind Upgrades Break Builds

The core problem with JavaScript package management isn’t finding outdated dependencies—npm outdated handles that. The problem is that upgrading to “latest” ignores peer dependency constraints, semver boundaries, and the reality that your lockfile exists for a reason.

When you run npm update, npm respects the version ranges in your package.json. It won’t jump from ^2.0.0 to 3.0.0 even if version 3 exists. This is intentional. But it also means genuine updates requiring range changes get stuck indefinitely.

ncu solves this by modifying package.json directly—updating version ranges—without touching node_modules or your lockfile. You control when installation happens.

Modern ncu Workflows for Node.js Dependency Management

Global installs are no longer the default mental model. With ncu v18+, run it directly via your package manager:

npx npm-check-updates
# or
pnpm dlx npm-check-updates
# or
bunx npm-check-updates

This checks for updates without modifying anything. You see what’s available, color-coded by semver level: red for major, cyan for minor, green for patch.

The critical flag is -u, which writes changes to package.json. But here’s what matters: this only updates the manifest. Your lockfile remains unchanged until you explicitly run npm install.

This separation enables a safer dependency update workflow:

  1. Run ncu -u --target minor to update package.json with non-breaking changes
  2. Run npm install to regenerate the lockfile
  3. Run your test suite
  4. If tests pass, commit both package.json and package-lock.json together

For major updates, handle them individually with ncu -u --filter package-name, review the changelog, then test.

Peer Dependencies and Compatibility Checking

Peer dependency conflicts cause most upgrade failures. A React component library might require React 18, but your project pins React 17. Blindly upgrading the library breaks the build.

ncu’s --peer flag checks peer dependency compatibility before suggesting updates. This prevents proposing upgrades that would immediately fail installation.

For stricter control, combine this with --target:

ncu --peer --target minor

This shows only updates that won’t break peer constraints and won’t cross major version boundaries.

Lockfiles and CI Pipeline Integration

Your lockfile represents a known-working state. Treat it accordingly.

In CI, always use npm ci instead of npm install. The ci command fails if package.json and package-lock.json are out of sync—exactly what you want. This catches situations where someone updated package.json but forgot to regenerate the lockfile.

For automated dependency update workflows in CI, the pattern looks like:

ncu -u --target patch
npm install
npm test

If tests pass, the pipeline commits the changes. If they fail, the update gets flagged for manual review.

Controlling Transitive Dependencies With Overrides

Sometimes the problem isn’t your direct dependencies—it’s what they depend on. A vulnerability three levels deep in your dependency tree requires updating a package you don’t control.

npm’s overrides field lets you force specific versions of transitive dependencies:

{
  "overrides": {
    "vulnerable-package": "2.0.1"
  }
}

This is a standard part of JavaScript package management. Use it when you need a security patch before upstream maintainers update their dependencies.

Conclusion

Dependency update automation doesn’t mean updating everything constantly. It means having a repeatable process that separates discovery from installation, respects semver boundaries, and keeps your lockfile in sync with your manifest.

ncu fits this workflow because it treats package.json updates as a distinct step. You decide what to upgrade, when to install, and when to test. The tool handles the tedious part—checking registries and modifying version ranges—while leaving the judgment calls to you.

Update patches weekly. Review minors monthly. Handle majors deliberately. Keep your lockfile committed. Your CI will thank you.

FAQs

npm update installs newer versions within your existing package.json version ranges but won't cross major version boundaries. npm-check-updates modifies the version ranges in package.json itself, allowing you to update to any version including major releases. ncu changes the manifest while npm update changes node_modules.

Yes. ncu works with any package manager since it only modifies package.json. Run it with pnpm dlx npm-check-updates or npx npm-check-updates regardless of your package manager. After ncu updates your package.json, use your preferred package manager to install the updated dependencies.

Use the reject flag with a package name or pattern. For example, ncu --reject typescript excludes TypeScript from updates. You can also use ncu --reject '/react.*/' to exclude multiple packages matching a pattern. This is useful for packages you want to update manually.

Running ncu -u only modifies package.json without installing anything. The risk comes from running npm install afterward without testing. Always run your test suite after updating and installing. Start with patch updates using ncu -u --target patch for the safest approach.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay