When a library is several major versions behind, upgrade it if the maintainers are active and the path is documented. Replace it if the project is unmaintained, the upgrade is a rewrite in all but name, or a simpler alternative covers what you use. Decide with five questions, not by habit.
The two options
Upgrade means moving through newer versions of the same library. Replace means swapping it for another library, a standard library feature, or code you write. Each has costs, and being far behind makes both larger.
Five questions
- Is it maintained? Look at recent releases, open security reports and how maintainers respond. OWASP lists unmaintained components as a risk and suggests monitoring for libraries that do not create security patches for older versions.
- Is there a documented upgrade path? A migration guide and a deprecation period, in line with the semantic versioning advice to deprecate in a minor release before removing in a major, reduce effort.
- How much of the library do you use? If you call two functions, replacement may be small. If it is woven through the code, upgrading is easier than ripping it out.
- What does the replacement cost? Include learning, testing, and new dependencies you introduce.
- Does the gap block anything else? If other libraries now require the newer API, staying is not neutral.
Decision table
| Answer pattern | Lean toward |
|---|---|
| Active project, clear guide, heavy use | Upgrade |
| Active project, small use | Upgrade or replace, whichever is cheaper |
| Unmaintained, small use | Replace |
| Unmaintained, heavy use | Replace in stages, with a wrapper first |
| Upgrade is effectively a rewrite | Compare with replacement seriously |
How to upgrade when far behind
- Read changelogs for each major you will cross.
- Step one major at a time, merging each, rather than jumping.
- Add tests around the behavior you rely on before starting.
- Keep each step in its own pull request.
How to replace safely
- Put a thin wrapper around the old library so call sites change only once.
- Build the new implementation behind the wrapper.
- Run both in tests or in a shadow mode if your system allows it.
- Remove the old library and its transitive packages when done.
Check the cost honestly
Estimate each path in engineer days using your own past upgrades as a guide. Add a risk buffer for unknowns, and decide with a leader who can trade this against roadmap work.
Document the decision
Write down the options considered, the choice, the owner and the review date. Future readers will need to know why.
Safeguard's SBOM and dependency scanning lists direct and transitive packages with their versions, and reachability analysis shows which outdated or vulnerable ones your code actually calls. Autonomous remediation can open fix pull requests; it is off by default and every category starts on Manual. You can try a free scan at gold.safeguard.sh/scan.
Try it yourself
Click through it at your own pace, or open it full screen. Find how widely a package is used across the project, which helps size a replacement.
Quick check
What if both options look equally costly?
Prefer the one that reduces long term risk, usually the supported and maintained path.
Can a wrapper fix everything?
No, but it localizes change so either path becomes cheaper and safer.
Sources
Last reviewed: 19 October 2026.