Contents
Dependencies should be updated regularly in small batches: security fixes immediately, minor versions weekly via automated pull requests, major framework versions on a planned basis soon after release. A project left alone for a couple of years eventually runs into unpatched vulnerabilities, incompatibility with new language versions and an upgrade that turns into a months-long project.
Here is why old dependencies are dangerous, how versions work, how to automate updates and how to guard against malicious packages.
Why are outdated dependencies dangerous?
A modern project consists of hundreds of third-party packages. Vulnerabilities are regularly found in each, and fixes ship only for current versions. The further behind a project falls, the more each next step costs.
- vulnerabilities — known holes in old versions are exploited automatically;
- end of support — old language and framework versions stop receiving fixes;
- incompatibility — a new library you need requires fresh versions of others;
- accumulated debt — jumping three major versions is far harder than three upgrades in turn;
- hiring — developers are reluctant to work on an old stack.
On other sources of debt, see technical debt.
How do you read version numbers?
Most packages follow semantic versioning: MAJOR.MINOR.PATCH. It tells you how risky an update is.
| Part | What changes | Update risk | Example |
|---|---|---|---|
| Patch | Bug fixes | Low | 3.4.1 → 3.4.2 |
| Minor | New backward-compatible features | Modest | 3.4.2 → 3.5.0 |
| Major | Breaking changes | High, migration needed | 3.5.0 → 4.0.0 |
Version ranges in the dependency file define what may update automatically, and the lock file pins the exact installed versions. Commit the lock file so everyone runs the same thing.
Photo: Unsplash
How do you automate updates?
Updates are automated with bots that regularly check for new versions and open pull requests. CI runs the tests, and if everything is green, patch updates can be merged with almost no human involvement.
{
"extends": ["config:recommended"],
"schedule": ["before 9am on monday"],
"packageRules": [
{ "matchUpdateTypes": ["patch", "minor"], "groupName": "minor and patch", "automerge": true },
{ "matchUpdateTypes": ["major"], "labels": ["major-update"], "automerge": false }
],
"vulnerabilityAlerts": { "labels": ["security"], "schedule": ["at any time"] }
}
Process rules:
- Patch and minor updates are grouped and arrive weekly.
- Security fixes arrive immediately with top priority.
- Major updates are reviewed by hand and planned as tasks.
- Do not enable auto-merge without good automated tests — see automated testing strategy.
How do you upgrade a major framework version?
A major framework upgrade is a small project: read the migration guide, update the code and related packages and check the whole application. The sooner after release you do it, the fewer changes it takes.
- upgrade one major version at a time without skipping;
- first remove everything deprecated in the current version;
- use automated code migration tools if available;
- check key packages for compatibility in advance;
- ship the upgrade as its own release, not together with new features.
On new PHP versions, see PHP 8.6 release candidate.
How do you guard against malicious packages?
Supply chain attacks — publishing a malicious version of a popular package or a package with a look-alike name — have become routine. Defence rests on controlling what is installed and from where.
- vet new dependencies before adding them: popularity, maintenance, number of their own dependencies;
- use the lock file and install strictly from it in CI;
- avoid updating to a version in its first days unless necessary;
- scan dependencies for known vulnerabilities in CI;
- restrict package install scripts where possible.
On other security measures, see OWASP Top 10 explained and secrets management.
In short
- Update dependencies regularly in small batches.
- Semantic versions show the risk: patch, minor, major.
- Automate update pull requests and verify them with tests.
- Upgrade major framework versions one at a time, on a plan, as a separate release.
- Guard against malicious packages: lock files, vetting new dependencies, scanning.
FAQ
How often should dependencies be updated?
Security fixes immediately. Minor and patch versions regularly, for example weekly in a batch. Major framework versions on a planned basis within a few months of release.
What if a library is abandoned?
Find a maintained replacement or fork, estimate the migration and plan it. If there is no replacement and the code is small, it is sometimes easier to bring the needed part into your own project.
Should the lock file be committed?
Yes, for applications it is essential. The lock file pins exact versions of every dependency so developers, CI and production all run the same thing.



