Skip to content
Back to skills

Upgrade Deps

ASecurity

Upgrade a Node repo's dependencies in three rounds (patch → minor → major) using npm-check-updates, respecting the project's release-age cooldown. Researches each update's changelog in parallel, bumps the uneventful ones silently, runs the tests, commits, and surfaces only the packages that need a human decision -- a few at a time, most severe first. Works in monorepos (--workspaces, syncpack). Use when the user runs /upgrade-deps, or asks to "upgrade deps", "bump dependencies", "update packa...

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 5, 2026
testingtypescriptgoreactnodegitapisecurity

Works with

  • terminal
  • cli
  • api

Security analysis

A100/100

Scanned October 5, 2026

npx -y skills add nvie/skills --skill upgrade-deps --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Upgrade Deps?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Upgrade Deps
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/nvie-upgrade-deps/badge)](https://www.skillsdirectory.com/skills/nvie-upgrade-deps)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: upgrade-deps
description: >
  Upgrade a Node repo's dependencies in three rounds (patch → minor → major)
  using npm-check-updates, respecting the project's release-age cooldown.
  Researches each update's changelog in parallel, bumps the uneventful ones
  silently, runs the tests, commits, and surfaces only the packages that need a
  human decision -- a few at a time, most severe first. Works in monorepos
  (--workspaces, syncpack). Use when the user runs /upgrade-deps, or asks to
  "upgrade deps", "bump dependencies", "update packages", or "run ncu".
---

# Upgrade deps

Get a repo's dependencies current with the least possible human attention.
The user's attention is the scarce resource: spend it only on packages that
genuinely need a decision. Everything that Just Works™ gets bumped, tested,
committed, and mentioned in a single line at the end.

The user can override the plan at any point ("skip majors today", "leave
`zod` alone", "just try them all"). Their instruction beats this document.

## Setup (once per run)

1. **Clean tree required.** If `git status --porcelain` shows changes, stop
   and ask. Never stash or discard anything.
2. **Package manager.** Detect from the lockfile (`pnpm-lock.yaml`,
   `yarn.lock`, `package-lock.json`, `bun.lock*`). Pass it to ncu as
   `-p <pm>`, and use it for installs.
3. **Monorepo?** If the root `package.json` has `workspaces`, or there's a
   `pnpm-workspace.yaml`, add `--workspaces` (root stays included by default).
   Bump a package to the same version everywhere it appears.
4. **Cooldown.** Only if the project configures one:
   - pnpm: `minimumReleaseAge` (minutes) in `pnpm-workspace.yaml` → `--cooldown <N>m`
   - yarn: `npmMinimalAgeGate` in `.yarnrc.yml` → convert to ncu's units
     (`d`/`h`/`m`)
   - npm/bun: check `.npmrc` / `bunfig.toml` for a release-age setting
   If none is configured, use no cooldown. If a setting exists but its unit is
   ambiguous, ask rather than guess.
5. **Verification command(s).** From the root `package.json` scripts (via
   `turbo run` if the repo uses turbo): `test` and `test:types`, whichever
   exist. No build, no lint. If the repo uses syncpack (dependency or config
   file present), add `syncpack lint` (or whatever syncpack script the repo
   defines).
6. **Baseline.** Run verification once before touching anything. Record
   pre-existing failures so they're never blamed on an upgrade. If the
   baseline is red, tell the user in one line and ask whether to proceed.

Keep a session-local **reject list**: packages the user decided not to
upgrade. Pass them as `--reject` to every later ncu call so they don't
resurface.

## A round

Rounds run in order: `-t patch`, then `-t minor`, then `-t latest` (majors).
Each round:

### 1. List

```
npx npm-check-updates -t <target> -p <pm> [--workspaces] [--cooldown X] [--reject a,b] --jsonUpgraded
```

Nothing to upgrade → say so in one line, move to the next round.

### 2. Research (parallel)

First grep the repo for each package's usage (imports, config files, CLI
invocations in scripts) so research is grounded in what *we* use.

Then spawn one subagent per package (general-purpose), all in a single
message. Each gets: package name, from → to, and our usage sites. Each must:

- Read the changelog for every version in the range: GitHub releases
  (`gh release view`), `CHANGELOG.md` in the repo (`npm view <pkg>
  repository.url`), or the npm page.
- Only if the changelog is vague or missing and our usage is non-trivial:
  inspect `npm diff --diff=<pkg>@<from> --diff=<pkg>@<to>`.
- Return exactly:
  - `verdict`: `trivial` or `attention`
  - `risk` (if attention), meaning how much harm it can do to the product if
    it's shipped or ignored:
    - `critical`: security fix we're exposed to, or possible data loss/corruption
    - `high`: silent behavior change in code we use, or breaks runtime code
    - `medium`: breaks tests/types/tooling (loud, so caught before it ships),
      or needs a decision
    - `low`: cosmetic, opt-in, or tooling-only consistency issues
  - `reason` (if attention): one line, citing our usage site if relevant

`trivial` = no change touches API surface we use, or only additive/fix
changes. Anything ambiguous about code we use is `attention`. Never pad a
trivial verdict with an explanation.

### 3. Bump the trivial ones

Upgrade all `trivial` packages together (`ncu -u --filter a,b,c ...`), install,
verify.

- **Green** → commit via `gcm --yolo "<round>-level dependency upgrades"`.
- **Red** → bisect: revert half the batch (restore `package.json` files +
  lockfile from `HEAD`, re-apply the other half, reinstall), verify, narrow
  down until the culprit(s) are isolated. Commit the green remainder.
  Culprits move to the attention list, with their risk re-assessed in light
  of what broke.

### 4. Report

Sort attention items by risk, then by how much of our code they touch.
Output, and nothing else:

```
Patch round: 3 need you.

| name        | from    | to      | reason                                                      | risk   |
|-------------|---------|---------|-------------------------------------------------------------|--------|
| zod         | 3.23.8  | 3.23.11 | `z.string().email()` regex tightened; we validate signup     | high   |
|             |         |         | emails with it (src/auth/schema.ts:14). Tests pass, but      |        |
|             |         |         | existing users with odd emails could fail re-validation      |        |
| vitest      | 2.1.3   | 2.1.5   | bumped → 4 tests in packages/core fail (fake timers)         | medium |
| @types/node | 22.7.4  | 22.7.9  | syncpack mismatch: apps/web pins 22.7.4 exactly              | low    |

Pick one (default: zod), or "all" to batch-try + bisect.

Upgraded patch-level: react, react-dom, tsup, prettier, eslint-plugin-react, typescript-eslint (+9 more)
```

Rules:

- **At most ~8 table rows** (half a terminal screen). If more items exist,
  the last row is `| …and msw, undici, hono (3 more) | | | next message | |`.
- Reasons are one line where possible; wrap only when the reason truly needs
  it. No mention of trivial packages beyond the final line.
- The final line lists everything committed this round. If it'd exceed one
  line, name the first few and `(+N more)`.
- Zero attention items → just the final line, then continue to the next
  round. (Still pause before majors if the user said so.)

### 5. Iterate

Work through items with the user, one at a time, their pick. Typical moves:

- They ask questions → answer tersely, from changelog/diff evidence.
- They say "try it" → bump, verify, report the result in a line or two.
- They say "all" → bump every attention item, verify, bisect on red,
  report only what broke.
- A fix on our side is needed → make it, verify, commit the upgrade + fix
  together via `gcm --yolo "<pkg> <from> → <to>"`.
- They decline → add to the reject list, move on.

**Formatter upgrades** (any formatter: prettier, biome, dprint, oxfmt,
prettier/biome plugins, …): never ask, always do
this as three separate commits:

1. the version bump
2. the reformat the new version causes in files that were already formatted
3. a reformat of files that already failed the format check before the bump

Skip any step that has no changes. Mention commits 2 and 3 in a line each
only if something in them deserves a look (e.g. a rewrap inside a code
block or formula). Otherwise they go on the final line like any other
upgrade.

Each green upgrade is committed as it lands. Pause only when something needs
the user. When the attention list is empty, the round is done → next round.

## Ground rules

- Never push. Never rewrite history. Commits only via `gcm --yolo`.
- Never leave the tree half-upgraded when pausing for the user: either
  committed or reverted to `HEAD`.
- Never claim a package is safe without having read its changelog (or diff).
  No changelog found and non-trivial usage → `attention`, reason "no changelog".
- Majors are almost never `trivial` unless our usage is clearly unaffected by
  every listed breaking change.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…