Plan a runtime upgrade by inventorying where it runs, choosing the newest supported target your dependencies allow, fixing deprecation warnings, testing in CI on both versions, rolling out gradually, and adding a check that blocks anything older from returning. Start at least a quarter before the end date.
Start with the calendar, work backward
Take the vendor's end date and subtract. Leave time for a canary rollout, for testing, for fixing dependency blockers and for the unexpected. For a large estate, begin two quarters ahead.
Remember that support windows differ. A Node.js line, a .NET release and a Python version each follow their own policy, and some are fixed length while others depend on release type. The .NET policy, for example, gives long term releases three years and standard releases two.
The plan
- Inventory. Find every build file, Dockerfile, CI config, serverless setting and base image that names the version. Search for version strings across all repositories.
- Pick the target. Choose the newest supported release that your key libraries support. Check each library's release notes or classifiers.
- Find blockers. List dependencies that do not support the target. Decide per blocker: update, replace, fork or drop.
- Turn on warnings. Make deprecation warnings visible in tests and fix them on the old version first. This splits the work into safe pieces.
- Dual run in CI. Run the test suite on the old and new versions in parallel for a few days.
- Rebuild and retest native parts. Compiled extensions, drivers and agents often need new builds.
- Roll out in rings: internal tools, then low risk services, then critical ones. Watch error rate, latency and memory.
- Clean up. Remove the old version from CI and base images.
- Prevent drift with a policy check.
Keep old versions from returning
Once you have moved, set a gate. A policy that fails a pull request when a Dockerfile or manifest names an unsupported runtime stops accidental regression. Pair it with a version file per repository so there is a single place to change next time.
Common traps
| Trap | Effect | Avoidance |
|---|---|---|
| Upgrading production first | Surprises at the worst time | Use staging and canary rings |
| Skipping dependency checks | Late discovery of a blocker | Do blocker analysis in week one |
| Forgetting build images | Old runtime stays in CI | Include CI and base images in scope |
| No owner | Work stalls | Name one per service |
Try it yourself
Click through the pull request gate and notice what blocks a change and what message the developer sees.
Click through it at your own pace, or open it full screen.
Quick check
How early should I start?
At least one quarter before the end date for one service, two or more for a large estate.
Should I upgrade runtime and dependencies together?
Usually no. Change one thing at a time so a failure points to one cause. Update blockers first, then the runtime.
Where Safeguard fits
Safeguard's policies and gates can block pull requests that reintroduce flagged components, and its dependency scanning shows the blockers. Try the free scan.
Sources
Last reviewed: 19 October 2026.