guides/free, forever
The Upgrade Treadmill Survival Guide
How to stop drowning in robot pull requests without going soft on security. Written for solo maintainers and shops small enough that "the person who handles dependencies" is you.
One thing before anything else: I build a tool in this space. It's called Upshift. It has a free tier, and it shows up exactly once in this guide, clearly labeled, sitting next to the free alternatives. Everything else here works with tools you already have. If any part of this reads like an ad, I got it wrong. Tell me and I'll fix it.
What is all this, and how do I make it work for me?
I run a lot of repos. Too many. (That's a different post.) Most mornings I open them to a pile of automated update requests I didn't ask for, each one bumping some package from a version that worked to a version that probably also works. Each one wants a review. Each one is, individually, tiny. Together they're a Tuesday I don't get back. For a long time I had two honest reactions, in that order: what is all this? And then: how do I make it work for me instead of against me?
I also figured, for a while, that this was a me problem. I'm self-taught, so I assumed everybody else had a system and I'd missed the class. So I went looking. Turns out the class doesn't exist, and the people who ARE the class are drowning too:
- Tidelift surveyed developers on maintenance and the headline was 30% of their time goes to code maintenance. The fine print says most respondents land somewhere between 11% and 50%, which honestly is scarier than the headline. And the single most time-consuming task? Moving to a new major version of a framework or library, with breaking changes in updated dependencies right behind it.
- An academic study of Dependabot found maintainers so buried in notifications that 11.3% of studied projects deprecated Dependabot entirely, and the rest tended to configure it toward fewer notifications just to cope.
- Filippo Valsorda, the guy who maintains the cryptography packages in the Go standard library, publicly called Dependabot a "noise machine" and recommended turning it off, after it "opened thousands of PRs against unaffected repositories" over a fix he described as one line in a method no one uses, scored with "a nonsensical made up CVSS v4 score."
- It got loud enough that GitHub shipped a brake pedal for its own robot: Dependabot now has a "cooldown" setting so it can be told to slow down.
So no. Not a you problem. The firehose is the default setting. Here's how I turned it into a faucet.
Step 1: Cut the noise at the source
The principle is simple: you don't need to know about every release the moment it exists. Security alerts, yes, immediately. Everything else can arrive once a week, in one batch, on a morning you chose.
Here's a dependabot.yml that does that. Every line is doing a job:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm" # or pip, cargo, gomod, bundler...
directory: "/"
schedule:
interval: "weekly" # updates arrive Monday, not whenever
day: "monday"
open-pull-requests-limit: 3 # the bot may hold 3 PRs open, not 30
cooldown:
default-days: 14 # wait 2 weeks after a release before proposing it
semver-major-days: 30 # majors wait a month
semver-minor-days: 14
semver-patch-days: 7 # patches wait a week
groups:
weekly-batch: # minors and patches: ONE combined PR
applies-to: version-updates
update-types:
- "minor"
- "patch"
What this buys you:
- One batch PR a week for minors and patches, instead of one PR per package per release.
- Cooldown means you stop being the free QA department for day-one releases. A version that's been out two weeks has had two weeks for somebody else to step on the rake. This is also a cheap supply-chain protection: compromised releases tend to get caught fast, and you were never in the blast window.
- Majors surface slowly and separately, which is right, because majors are work (see Step 2).
The field names above are current against GitHub's Dependabot options reference as of July 2026. The numbers are my opinions, not physics. Tune them.
One thing you do NOT slow down: security updates. Cooldown and grouping here apply to version updates. Leave Dependabot security updates on, and let them come through the moment they exist. The whole point of quieting the routine noise is so the real alarm is audible.
If you're on Renovate instead, same doctrine, different file:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"schedule": ["before 9am on monday"],
"prConcurrentLimit": 3,
"minimumReleaseAge": "7 days",
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch"],
"groupName": "weekly non-major batch"
}
]
}
minimumReleaseAge is Renovate's cooldown. The grouping rule folds every minor and patch into one PR with one title. Option names checked against the Renovate docs, same date, same disclaimer.
Do the arithmetic on your own repo. If the bot was averaging a PR per package per week across a dozen active dependencies, you just went from a dozen interruptions to one batch, plus the occasional major, plus real security alerts. That's most of your Tuesday back, and you gave up nothing except being first in line to test strangers' releases.
Step 2: Triage like a maintainer
The bots treat every update the same. That's the actual bug. Here's the order that matters, and it's short:
1. Security fixes that actually reach your code. Not every CVE in your tree is your emergency. This is Valsorda's point from up top: scanners flagged thousands of repos for a fix he described as one line in a method no one uses. The question that matters is "does my code ever call the vulnerable thing?" If yes: drop what you're doing. If no, or you can't tell: it goes in this week's batch, near the front. Merging a patch bump is cheap either way. Panicking is the expensive part, so save it for reachable problems.
2. Majors of things you directly depend on. The survey receipt from earlier says major migrations are the single most time-consuming maintenance task there is. So believe it: a major is not a review, it's a PROJECT. Schedule it like one. One major at a time, read the changelog first, and give it a calendar slot instead of letting it squat in your PR list radiating guilt. A major in your web framework is a week. A major in your test runner is a Tuesday chore. Knowing which is which before you start is most of the job.
3. Everything else, batched. Minors and patches, one combined PR, on your schedule. Tests green, merge, close the tab. You do not owe every version bump a meditation.
Step 3: Every upgrade is a transaction
Here's the doctrine that took me embarrassingly long to adopt: never step forward until you know the way back. Snapshot, test, rollback. Every upgrade, even the boring ones. ESPECIALLY the boring ones, because the boring ones are the ones you merge half-asleep.
The plain git version costs nothing:
git switch -c upgrade-batch-2026-07-18 # snapshot: a branch, with your lockfile committed
npx npm-check-updates -u # see and apply what's available (free tool, not mine)
npm install
npm test # the actual verdict
Tests green: merge it and move on. Tests red: delete the branch and walk away. That's the whole trick. The branch is your snapshot, the lockfile is your time machine, and a failed upgrade costs you ten minutes instead of an afternoon of archaeology.
The labeled example: this is my tool. Upshift's free tier wraps that exact loop into one command, because I got tired of doing the ceremony by hand:
npm install -g upshift-cli
upshift scan # what's outdated
upshift upgrade react # upgrade, run your tests, auto-rollback if they fail
upshift upgrade --all-minor
upshift rollback # restore the previous state, any time
Honest status, because you deserve the same receipts I demand from everyone else: it's early. It moved 70 downloads on npm last week and some of those were me. The free tier does scan, upgrade, and rollback on one repo, which is the part this guide cares about. There are paid AI tiers; they are not what I'm pointing you at, and nothing in this guide needs them. If you'd rather stay vendor-neutral, the git version above is the same doctrine and I will not be hurt.
One requirement, and it applies to the git version just as much: you need a test script. If your package.json has no "test", upshift says so out loud and upgrades without a net (no auto-rollback, because there is no verdict to roll back on). I know this because I ran it on one of my own repos and got the warning. No tests means no safety net, whatever tool you use. If that is your repo, the first upgrade project worth scheduling is a "test" script that at least builds the thing.
Step 4: When paying for help is the right call
I give this guide away, but I'm not going to pretend money never belongs in the picture. Three cases where paying is the smart move, and one where it isn't:
Pay for a major migration that's bigger than your team. If a framework major means touching hundreds of files, that's the top task on the survey for a reason. Hiring help for a bounded migration project is buying an outcome. Just scope it like a project (this migration, this codebase, done means done), not a subscription that outlives the problem.
Pay for security triage when the flood is real. The paid security scanners sell reachability analysis: figuring out whether a CVE actually touches your code, at scale, automatically. Notice what's being sold there. The flood arrives free of charge, and the filter costs money. If you're maintaining a handful of repos, the triage order in Step 2 IS your filter. If you're responsible for fifty, buying the filter is honest math.
Pay the maintainers. The updates you're drowning in are written by people in worse shape than you: Tidelift's maintainer report found 60% of open source maintainers are unpaid, and 44% of those who quit cite burnout. Every unmaintained package eventually becomes your forced migration. A few dollars a month through GitHub Sponsors or Open Collective to the packages you actually depend on is not charity. It's upkeep on your own foundation.
Don't pay to stand still. If a service's pitch boils down to "we click the update button so it doesn't break," check whether Steps 1 through 3 just did that for the price of a config file. Sometimes the answer is still yes, pay (you have no dev on staff, fine, that's real). But know what you're buying before the invoice makes the decision for you.
Honest status of this guide
What's solid: every config field name was checked against the official GitHub and Renovate docs in July 2026, and every statistic links to its source, which I read. What's opinion: the cooldown day-counts and PR limits are my defaults, not laws. What's missing: the examples lean npm because that's where I live; the doctrine (batch, cooldown, triage, snapshot-test-rollback) ports to pip, cargo, gomod, and bundler, but you'll be translating the configs yourself.
I thought surviving the bots was going to be simpler than it turned out to be. I was wrong, and it cost me a lot of Tuesdays to learn what's in this page. If a config block here saves you one of yours, pass the guide along to somebody else who's drowning. Deal?
Written by Jeff Adkins (jeffadkins.dev). Disclosure, one more time: Upshift, mentioned once above, is my product; its free tier is free and its paid tiers were not pitched here on purpose.
This guide is licensed under CC BY-SA 4.0. Copy it, translate it, fix it, teach from it, republish it, no permission needed. The ShareAlike part means your improved version stays shareable too. That's the point.