Back to blog
Article

A dependency update cadence a three-person team can keep

A dependency update cadence a three-person team can keep
S

StriveBit

4 min readField Notes

A dependency update cadence a three-person team can keep

Our `npm outdated` output on a client's Next.js project had 47 entries. Fourteen were major versions behind. The app worked fine, and it had worked fine for eleven months, which is exactly the problem — nothing forces you to look at this until something breaks.

We tried quarterly dependency sprints. We blocked a full week, ran `npm audit fix`, upgraded everything, and spent three days debugging a regression in a date picker that a patch release introduced. The client paid for that week, and the only visible outcome was that the date picker worked again.

Now we do something smaller and more frequent.

On the first working day of each month, we pull the latest advisory reports for every project we maintain. We use `npm audit --json` and `pip-audit --format json`, pipe the output to files, and diff them against the previous month. New advisories get triaged in the first thirty minutes of the day. If something is critical or high severity and remotely exploitable, we patch it that week. Medium and low go on a list.

For non-security updates, we pick one project per month and update its dependencies. Not all projects — one. We rotate through. A project with eight dependencies gets updated more often than one with sixty, but every project gets its turn roughly every quarter.

The update itself is mechanical. We bump patch and minor versions first, run the test suite, and deploy. Then we look at major versions.

Major versions are where we make deliberate decisions to skip. We skip most of them. Upgrading from React 17 to 18 in a stable app that isn't actively getting new features is not worth the risk unless we're already touching that code for a client request. The React 18 upgrade on one project took two days because of changes to `useEffect` timing that surfaced a subtle bug in a third-party modal library. Two days of unbilled time, because we couldn't justify charging the client for an upgrade they didn't ask for.

What we do instead is track what we skipped and why.

We keep a file called `UPGRADES.md` in each project root. It looks like this:

# Deferred upgrades

## Next.js 13 -> 14
Deferred: 2024-03-04
Reason: App Router migration not requested by client. Server Actions
  used in two forms. Partial migration would create two routing paradigms.
Revisit: When client requests new pages or we touch routing.

## Prisma 4 -> 5
Deferred: 2024-03-04
Reason: Breaking changes to `prisma migrate` CLI. Custom migration
  scripts would need review. No security advisories blocking.
Revisit: Next quarter or if advisory is filed.

The file is short. Each entry has a date, a reason, and a trigger for revisiting. When we do quarterly project reviews, we read through the file and decide whether any of the deferred upgrades should move into the current month's work.

This sounds like overhead, and it is — about twenty minutes per project per month. But the alternative is worse. We've taken over projects from other shops where the dependencies were two years behind, the lockfile was in git but nobody remembered why certain versions were pinned, and the first upgrade attempt broke the build in four places. That kind of debt takes a week to clear, and the client doesn't want to pay for it because they don't see anything change.

The cadence we keep is deliberately modest. One project per month, one pass through advisories, one update to the deferred list. It doesn't catch everything. A major release of a library we depend on heavily might sit deferred for six months. But when we do upgrade, we know what we deferred, why we deferred it, and what changed in the meantime. That's worth more than being on the latest version of everything.

The projects we maintain stay within one major version of their core frameworks. That's the line we hold.

Back to all articles

Ready to build something great?

We help ambitious teams build software that lasts. If you're interested in working with us or want to discuss your project, let's connect.

Get in touch