Use only-if-needed, pip's default, when you want the smallest change. It upgrades a dependency only if it no longer satisfies the new parent requirement. Use eager when you deliberately want every dependency raised, accepting a larger blast radius. For a single advisory, name the vulnerable package instead of using either strategy broadly.
Two flags that people mix up
Pip has two separate controls. The upgrade flag acts on direct requirements, meaning what you typed on the command line or listed in a requirements file. The upgrade-strategy flag acts on indirect requirements, the dependencies of those direct packages. The pip documentation states this split plainly, and it explains many surprises.
Suppose you run an upgrade of a package called SomePackage, and it depends on SomeDependency. Both are installed but not at the latest version. With the default strategy, only SomePackage moves, and SomeDependency changes only if the new SomePackage demands a higher minimum. With eager, both move.
Definitions
- only-if-needed: upgrade a dependency only if it does not satisfy the new parent requirements. This is the default.
- eager: upgrade all dependencies regardless of whether they still satisfy the parent requirements.
The pip docs note that the default changed in pip 10.0 because eager was found to be breaking when it upgraded conflicting dependencies. They also mention that a proposal for an upgrade-all command is being considered as a safer alternative to eager upgrading.
Which one for a vulnerability fix
| Situation | Choice | Why |
|---|---|---|
| One transitive package is flagged | Name that package and upgrade it | Smallest change you can test |
| Parent has a fixed release that raises the minimum | Upgrade the parent, default strategy | pip raises the child only as needed |
| Many advisories across the tree | Eager in a branch, then test hard | Larger change, needs a full test run |
| Production hotfix | Default strategy plus exact version | Least risk of side effects |
Eager looks attractive during a security push, but it changes packages that had no advisory. Each of those is an untested behavior change. If you want everything current, do it as a scheduled maintenance task with a full test run, separate from the urgent fix.
A safe sequence
- Record the current state with a freeze of installed versions.
- Upgrade only the package named in the advisory, or its parent if the child is transitive.
- Compare the freeze before and after. Every extra line that moved is something to test.
- Run pip check to catch incompatible requirements.
- Run the test suite, then redeploy.
If the flagged package does not move after step 2, a parent probably caps it. A constraints file can set a floor, but it cannot override a parent's upper bound, so you may need to upgrade the parent.
Try it yourself
Click through it at your own pace, or open it full screen. Notice that a fix being available does not tell you how many other packages the upgrade touches.
Where Safeguard fits
Safeguard scans dependencies, runs reachability analysis to show which findings your code can actually reach, and can open fix pull requests through autonomous remediation. That last feature is off by default and every category starts on Manual, so a person approves each change. You can try a free scan on a repository first.
Quick check
Does upgrading a package also upgrade its dependencies by default?
Only if the new version requires a higher minimum. Otherwise pip leaves the dependency alone under only-if-needed.
Is eager ever the right choice?
Yes, for a planned maintenance upgrade with a full test run. It is a poor fit for an urgent single-advisory fix.
Sources
Last reviewed: 19 October 2026.