Dependency Upgrades Are Reliability Work

The least popular reliability work there is, and the one where the cost of skipping it is not linear.

Maintenance Christopher Roos 3 min read

Upgrading dependencies is the least popular reliability work there is. It produces no visible feature, it occasionally breaks something, and the benefit is entirely counterfactual. It is also one of the highest-leverage habits a team can build, and the cost of skipping it is not linear.

Debt compounds, and the interest rate rises

A dependency one minor version behind is a fifteen-minute upgrade. Two years behind, it is a project: the API changed, the config format changed, the thing it depends on also moved, and the migration guide assumes you did the intermediate steps.

The trap is that the cost of upgrading rises faster than the time elapsed, while the perceived urgency stays flat at zero. So the rational-seeming choice each individual week is to defer, and the aggregate result is a system nobody can safely change.

The version of this that actually hurts is discovering a critical vulnerability in something you are eight major versions behind on, and finding out that the patch is only available on a line you cannot reach in an afternoon. Now an urgent security fix is a three-week migration, performed under pressure.

Small and frequent beats large and scheduled

The teams that stay current do it continuously and boringly. Automated dependency updates opening pull requests, a pipeline that runs the full test suite against them, and a standing expectation that they get reviewed like anything else.

This only works if two conditions hold. The test suite has to be trusted enough that a green run means something, and the pipeline has to be fast enough that reviewing a dozen small updates is not a day of waiting. If either is missing, the updates pile up unmerged, which is the same debt in a different queue.

Separate the two kinds of upgrade

Patch and minor updates should be near-automatic. Batch them, run the tests, merge them if green. There is no useful judgment being applied by reading each one, and pretending otherwise just adds latency.

Major versions are different work. They deserve a ticket, a read of the changelog, and a deliberate decision about timing. Treating them the same way as a patch bump is how you end up with an automated pull request that quietly changes behavior nobody was watching for.

Track the age, not the count

The number of outdated dependencies is a bad metric. It swings wildly for reasons outside your control and says nothing about risk. The useful number is how far behind the oldest thing is, and whether that figure is going up or down over a quarter.

One dependency four years stale is a bigger problem than forty that are one release behind, and a count treats them identically.

The argument to make

If you need to justify the time, the honest framing is optionality. A system whose dependencies are current can adopt a security patch in an afternoon. A system two years behind cannot, and will discover this at the worst possible moment. You are not buying features, you are buying the ability to move quickly later, at a time you do not get to choose.