---
title: "How to Update All Node.js Dependencies to Latest Version"
description: "Learn how to update all Node.js dependencies with npm-check-updates, interactive mode, doctor mode, and supply chain security best practices."
date: 2026-07-14
categories: ["tools"]
tags: ["node","npm","javascript"]
---

import Button from "@components/widgets/Button.astro";
import Notice from "@components/widgets/Notice.astro";
import ListCheck from "@components/widgets/ListCheck.astro";
import Tabs from "@components/widgets/Tabs.astro";
import Tab from "@components/widgets/Tab.astro";

Node.js has a large ecosystem of packages you can pull into your projects. These packages are your **dependencies**, managed by **npm** (Node Package Manager) or alternative tools like pnpm, Yarn, and Bun.

Dependencies live in a file called **`package.json`** at the root of your project. This file tracks your project's name, version, scripts, and every dependency it needs. Here's a typical entry:

```json
"dependencies": {
  "express": "^4.17.1"
}
```

The version number uses semantic versioning prefixes. The `^` prefix means "any version compatible with 4.x.x" -- so `^4.17.1` accepts anything from 4.17.1 up to (but not including) 5.0.0. The `~` prefix is more restrictive, accepting only patch updates within the same minor version (e.g., `~4.17.1` means 4.17.x). An exact version like `4.17.1` locks to that specific release.

To install dependencies, run `npm install` in your terminal. This downloads packages from the npm registry into a `node_modules` folder.

If you don't have Node.js installed yet, check out how to [install Node.js using NVM](/install-nodejs-using-nvm-macos-ubuntu/) -- it's the recommended way to manage multiple Node.js versions. Fish shell users can also see [how to use NVM with Fish Shell](/nvm-fish-shell/).

Keeping those dependencies updated is important. Outdated packages accumulate security vulnerabilities, miss performance improvements, and eventually become incompatible with each other. This guide covers how to update Node.js dependencies safely in 2026.

## Why you should update Node.js dependencies regularly

Regular dependency updates give you:

<ListCheck>
<ul>
  <li>Security patches for known vulnerabilities</li>
  <li>New features and API improvements</li>
  <li>Performance optimizations from upstream changes</li>
  <li>Bug fixes that resolve issues in your codebase</li>
  <li>Better compatibility with the latest Node.js versions</li>
</ul>
</ListCheck>

In 2025 alone, security researchers flagged nearly 455,000 malicious packages on npm. Supply chain attacks are a real and growing threat. Running outdated dependencies exposes your project to known exploits that have already been patched upstream.

But updating isn't risk-free.

<Notice type="warning" title="Breaking changes">
Major version bumps (e.g., Express 4.x to 5.x) can include breaking API changes. Always check the changelog before upgrading across major versions. A function you rely on might have been renamed, removed, or its parameters changed. Use a staged update strategy (patch first, then minor, then major) to isolate problems.
</Notice>

With the right tools and workflow, you can update without breaking production.

## Understanding semantic versioning (semver)

Before getting into update commands, understand how npm version numbers work. Every package follows the **MAJOR.MINOR.PATCH** convention:

| Version Part | What Changes | Example |
|---|---|---|
| **MAJOR** (1st) | Breaking changes, incompatible API changes | `4.17.1` → `5.0.0` |
| **MINOR** (2nd) | New features, backward-compatible | `4.17.1` → `4.18.0` |
| **PATCH** (3rd) | Bug fixes, security patches, backward-compatible | `4.17.1` → `4.17.2` |

<Notice type="info" title="Semver prefix quick reference">
`^4.17.1` (caret) -- allows minor and patch updates within 4.x.x. This is the npm default.
`~4.17.1` (tilde) -- allows only patch updates within 4.17.x.
`4.17.1` (exact) -- locks to that exact version. No automatic updates.
`>=4.17.1` -- any version at or above 4.17.1.
</Notice>

Most `package.json` files use `^` prefixes. This means running `npm install` will pull the latest compatible patch or minor release -- but never a new major version. To jump across major versions, you need a tool like npm-check-updates.

## How to update all Node.js dependencies using npm-check-updates

[npm-check-updates](https://www.npmjs.com/package/npm-check-updates) (ncu) is the go-to tool for bumping dependencies to their latest versions. It rewrites the version numbers in your `package.json` without installing anything. You run `npm install` afterward. As of 2026, ncu is at v22+ and requires Node.js `^20.19.0 || ^22.12.0 || >=24.0.0` with npm `>=10.0.0`.

### 1. Install npm-check-updates

You have two options: global install or npx.

<Tabs>
<Tab name="npx (Recommended)">
```sh
npx npm-check-updates
```

Runs ncu without installing anything globally. This is the recommended approach. It always uses the latest version and doesn't pollute your global npm packages.
</Tab>
<Tab name="Global install">
```sh
npm install -g npm-check-updates
```

Installs ncu globally so you can run `ncu` directly from any project. You'll need to run `npm update -g npm-check-updates` periodically to keep it current.
</Tab>
</Tabs>

<Notice type="warning" title="Important: npx ncu does not work">
Use the full name `npx npm-check-updates`. The short form `npx ncu` resolves to a completely different (unrelated) package on npm. This is a common mistake that leads to confusing errors.
</Notice>

### 2. Check which packages are outdated

Run `ncu` in your project directory to see which packages have newer versions available:

```sh
ncu
```

Output looks like this:

```
 express          ^4.21.0  →   ^5.1.0
 cors             ^2.8.5   →   ^3.0.0
 dotenv           ^16.4.5  →   ^16.4.7
 uuid             ^9.0.1   →   ^11.1.0
```

You can also use npm's built-in command as an alternative:

```sh
npm outdated
```

The difference: `npm outdated` shows what's available within your current semver ranges. `ncu` shows the absolute latest versions regardless of semver constraints -- including major version jumps.

### 3. Update package.json to latest versions

To rewrite `package.json` with the latest version numbers:

```sh
ncu -u
```

This updates the version strings in `package.json` but does **not** install anything yet. You'll see output like:

```
Upgrading /home/user/myproject/package.json
[====================] 5/5 100%

 express     ^4.21.0  →   ^5.1.0
 cors        ^2.8.5   →   ^3.0.0
 dotenv      ^16.4.5  →   ^16.4.7
 uuid        ^9.0.1   →   ^11.1.0
 morgan      ^1.10.0  →   ^1.10.1

Run npm install to install new versions.
```

### 4. Install the updated packages

Now install the new versions:

```sh
npm install
```

This downloads the updated packages into `node_modules`. Run your tests afterward to make sure nothing broke.

### Quick reference: npm-check-updates commands

| Command | What It Does |
|---|---|
| `ncu` | Show outdated packages (read-only) |
| `ncu -u` | Update `package.json` to latest versions |
| `ncu -i` | Interactive mode -- pick packages one by one |
| `ncu --doctor -u` | Iteratively test upgrades to find breaking changes |
| `ncu --target patch` | Only suggest patch-level updates |
| `ncu --target minor` | Only suggest minor + patch updates |
| `ncu --filter express` | Only check specific packages |
| `ncu --reject react` | Exclude specific packages from updates |
| `ncu --dep prod` | Only check production dependencies |
| `ncu --cooldown 7` | Skip packages published less than 7 days ago |

## Using interactive mode to update selectively

When you don't want to update everything at once, use interactive mode:

```sh
ncu -i
```

This displays a list of outdated packages with checkboxes. Use arrow keys to navigate and the spacebar to toggle individual packages on or off. Press Enter to apply your selections.

Interactive mode is useful when:
- You want to update a few safe packages first and handle risky ones later
- You're doing a triage pass on a project with many outdated dependencies
- You want to skip packages that you know have breaking changes

<Notice type="info" title="Organize output by update type">
Add `--format group` to organize the list by major, minor, and patch updates:
```sh
ncu -i --format group
```
This makes it easy to quickly approve all patch updates and skip major ones.
</Notice>

## Using doctor mode for safe major upgrades

Major version upgrades are the riskiest part of dependency updates. Doctor mode handles this automatically by iteratively upgrading packages and running your test suite to find exactly which upgrade breaks things.

```sh
ncu --doctor -u
```

Here's how it works:

1. Runs your test suite first to establish a baseline (tests must pass initially)
2. Upgrades all packages to their latest versions
3. Runs tests again
4. If tests fail, it uses a binary search approach. It reverts half the upgrades, tests, and narrows down until it finds the specific package causing the failure.
5. Keeps all passing upgrades and reverts only the breaking one
6. Repeats until all packages are tested

<Notice type="success" title="Recommended for major upgrades">
Doctor mode is the safest way to handle large version jumps. Instead of guessing which package broke your app, the tool pinpoints it for you. The catch: you need a working test suite, and it requires the `-u` flag to actually apply changes.
</Notice>

Available since ncu v8, doctor mode has become a standard part of dependency update workflows. It works with any test runner that exits with a non-zero code on failure.

## Targeting specific update levels with ncu

Sometimes you don't want the latest of everything. ncu's `--target` flag lets you control how aggressive updates are:

```sh
# Only patch updates (bug fixes, security patches)
ncu --target patch

# Minor + patch (new features, no breaking changes)
ncu --target minor

# Stay within current semver range (same as what npm install would do)
ncu --target semver

# Pre-release versions tagged @next
ncu --target @next

# Highest version number regardless of dist-tag
ncu --target greatest
```

A staged approach works well in practice:

1. `ncu --target patch -u && npm install && npm test` -- safe, apply immediately
2. `ncu --target minor -u && npm install && npm test` -- usually safe, test after
3. Handle major upgrades individually with doctor mode

You can also filter which packages to update:

```sh
# Only update specific packages
ncu --filter express,cors

# Update everything except specific packages
ncu --reject react,react-dom

# Use wildcards
ncu --filter "@types/*"

# Only production dependencies (skip devDependencies)
ncu --dep prod
```

## Updating dependencies with pnpm, Yarn, and Bun

npm-check-updates works with any package manager (it only modifies `package.json`). But each package manager also has its own built-in update commands:

<Tabs>
<Tab name="npm">
```sh
# Check outdated (within semver range)
npm outdated

# Update within semver ranges
npm update

# Update package.json to latest + install
npx npm-check-updates -u
npm install
```
</Tab>
<Tab name="pnpm">
```sh
# Check outdated
pnpm outdated

# Update within semver ranges
pnpm update

# Update to latest versions (ignoring semver ranges)
pnpm update --latest

# Interactive update mode
pnpm update --interactive --latest
```
</Tab>
<Tab name="Yarn">
```sh
# Check outdated (Yarn 1.x / Classic)
yarn outdated

# Update within semver ranges
yarn upgrade

# Interactive upgrade (Yarn Berry / 2+)
yarn up -i

# Update to latest (Yarn Berry)
yarn up --interactive
```
</Tab>
<Tab name="Bun">
```sh
# Update dependencies within semver ranges
bun update

# Update to latest versions
bun update --latest

# Check for outdated packages
bun outdated
```

For a deeper dive, see [how to update packages in Bun](/bun-update-packages/). You can also read our comparison of [Bun vs npm, Yarn, pnpm, and others](/bun-package-manager/) to choose the right package manager for your project.
</Tab>
</Tabs>

All of these tools respect `package.json` version ranges by default. To jump across major versions, you typically need the `--latest` flag (pnpm, Bun) or a tool like ncu.

## Supply chain security: dependency cooldowns and release age

This section didn't exist when this article was first written. Supply chain security has since become a core part of dependency management.

Supply chain attacks on npm have exploded. In 2025, security researchers identified nearly 455,000 malicious packages on the npm registry. Attackers hijack popular package names, inject malware into legitimate updates, or typosquat common package names. The Axios compromise in March 2026 showed that even widely-trusted packages aren't immune.

The defense: **dependency cooldowns**, refusing to install packages that were published too recently.

### Setting a minimum release age in .npmrc

Starting with **npm 11.10.0** (February 2026), you can configure a `min-release-age` in your `.npmrc` file:

```
min-release-age=7d
```

This tells npm to reject any package published less than 7 days ago. The logic is simple: if a package update contains malware, it will likely be detected and removed by the community within a few days. Waiting a week gives security researchers time to flag malicious releases.

### Using cooldown with npm-check-updates

ncu v20+ auto-detects cooldown settings from your package manager config:

- npm: reads `min-release-age` from `.npmrc`
- pnpm: reads `minimumReleaseAge` from `.npmrc`
- Yarn Berry: reads `npmMinimalAgeGate` from `.yarnrc.yml`

You can also set it directly with ncu:

```sh
ncu --cooldown 7
```

This skips any package published less than 7 days ago when checking for updates.

<Notice type="error" title="npm v12 coming July 2026">
Major security changes are landing in npm v12. By default, install scripts from dependencies will **not run** without explicit approval. Other defaults include `--allow-git: none` and `--allow-remote: none`. To prepare:

- Run `npm approve-scripts` to whitelist trusted packages now
- Run `npm deny-scripts` to explicitly block suspicious ones
- Test your CI/CD pipelines with these restrictions before v12 drops

These changes stop a common attack vector where malicious packages execute arbitrary code during `npm install`.
</Notice>

<Notice type="warning" title="Protect your projects now">
Even before npm v12, you can take these steps today:
1. Add `min-release-age=7d` to your `.npmrc`
2. Use `ncu --cooldown 7` when checking for updates
3. Run `npm audit` regularly to catch known vulnerabilities
4. Set up automated dependency updates with Dependabot or Renovate (covered below)

If you're deploying Node.js apps with Docker, see our guide on [top Docker commands you need to know](/docker-commands/) for container security best practices.
</Notice>

## Running security audits with npm audit

After updating dependencies, always run a security audit:

```sh
npm audit
```

This checks your installed packages against the npm security advisory database and reports known vulnerabilities. Output includes the severity level (low, moderate, high, critical), the affected package, and the path through your dependency tree.

To automatically fix vulnerabilities:

```sh
# Fix within semver ranges (safe)
npm audit fix

# Fix with major version bumps (may break things)
npm audit fix --force
```

<Notice type="info" title="npm audit caveats">
npm audit has a signal-to-noise problem. It often flags vulnerabilities in transitive dependencies (packages your packages depend on) that don't actually affect your runtime. A "high severity" audit finding in a dev-only package that only runs during testing is different from one in your production dependency path.

Use `npm audit --omit=dev` to focus on production dependencies. Don't panic over every audit finding. Evaluate whether the vulnerable code path is actually used in your project.
</Notice>

## Automating dependency updates with Dependabot and Renovate

Manual updates work for small projects. For anything with CI/CD, automate it.

### Dependabot

GitHub's built-in dependency update bot. Configure it in `.github/dependabot.yml`:

```yaml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    reviewers:
      - "your-github-username"
```

Dependabot creates pull requests automatically when new versions are available. It's free for all GitHub repositories and requires zero infrastructure.

### Renovate

Open source, self-hostable, and far more configurable. Advantages over Dependabot:

- **Grouping**: Combine multiple related updates into a single PR (e.g., all `@types/*` packages)
- **Automerge**: Auto-merge patch updates that pass CI
- **Schedules**: Run updates only during business hours
- **Custom rules**: Match packages by pattern, version type, or source

Configure via `renovate.json` in your repo root:

```json
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:base"],
  "packageRules": [
    {
      "matchUpdateTypes": ["patch"],
      "automerge": true
    },
    {
      "matchPackagePatterns": ["@types/*"],
      "groupName": "type definitions"
    }
  ]
}
```

Use Dependabot if you're on GitHub and want something that works with zero config. Use Renovate if you need grouping, automerge, or finer control over update behavior.

## Best practices for updating Node.js dependencies safely

### Use a staged update strategy

Don't update everything at once. Work in stages:

1. Create a branch: `git checkout -b deps-update`
2. Update patch versions first: `ncu --target patch -u && npm install && npm test`
3. Update minor versions: `ncu --target minor -u && npm install && npm test`
4. Handle major versions individually: `ncu --doctor -u`
5. Commit and merge

This isolates problems. If something breaks, you know it's in the most recent stage.

### Create a .ncurc configuration file

Save project-specific ncu settings in `.ncurc.json`:

```json
{
  "reject": ["mongoose", "sequelize"],
  "target": "minor",
  "upgrade": true
}
```

This keeps certain packages pinned (maybe you know they have breaking changes) and sets a default update level. Run `ncu` without flags and it reads this config automatically.

### Handle peer dependency conflicts

When packages require specific versions of shared dependencies, conflicts arise:

```sh
# Check for peer dependency issues
ncu --peer
```

If you hit peer dependency errors after updating, try:

```sh
npm install --legacy-peer-deps
```

This tells npm to use the older, more lenient dependency resolution. It's a workaround, not a fix, but it unblocks you while you sort out the conflict.

For a more permanent solution, use the `overrides` field in `package.json` to force specific versions:

```json
{
  "overrides": {
    "some-transitive-dependency": "^2.0.0"
  }
}
```

### General workflow tips

<ListCheck>
<ul>
  <li>Always work in a git branch when updating dependencies</li>
  <li>Update frequently, weekly or monthly, to avoid accumulating debt</li>
  <li>Read changelogs for major version updates before applying them</li>
  <li>Pin exact versions in production, use ranges for dev tools</li>
  <li>Set up CI to run tests on dependency update PRs</li>
  <li>Use <code>min-release-age</code> in .npmrc for supply chain protection</li>
</ul>
</ListCheck>

Make sure your git workflow is solid. [Linking GitHub with SSH](/link-github-with-ssh-maco-linux/) makes pushing branches and reviewing PRs frictionless.

## Conclusion

Updating Node.js dependencies doesn't have to be scary. The workflow is straightforward:

1. **Check** what's outdated with `ncu`
2. **Update** in stages (patch → minor → major)
3. **Test** after each stage
4. **Commit** and merge

What's changed since this article was first published is the security environment. Supply chain attacks are real and growing. Configuring dependency cooldowns, running `npm audit`, and setting up automated updates with Dependabot or Renovate are no longer optional best practices. They're baseline hygiene.

Start by adding `min-release-age=7d` to your `.npmrc` today. Set up a weekly Dependabot schedule. Use doctor mode when you need to tackle major version jumps.

<Button text="Install Node.js with NVM" link="/install-nodejs-using-nvm-macos-ubuntu/" variant="solid" color="blue" size="md" icon="arrow-right" />
<Button text="Host Node.js Apps with CloudPanel" link="/install-cloudpanel-host-nodejs/" variant="outline" color="blue" size="md" icon="arrow-right" />