Dependency Updates: The Maintenance Chore That Decides Whether You Get Hacked

A practical approach to updating dependencies in Laravel, Vue, and Go projects — why npm audit noise hides real problems, what to update weekly versus never on a schedule, and how to avoid the two failure modes: rot and churn.

Dependency updates: the maintenance chore that decides whether you get hacked

Every web app is a pile of other people's packages. Laravel pulls in dozens of dependencies, a Vue project pulls in hundreds, and each one is code you didn't write running in production under your name. When a CVE lands in one of them, the question is not whether you update, but how fast.

The problem is that "how fast" depends on knowing what you have, and most teams don't. This is the process we run on projects we maintain.

Know what you actually ship

composer.lock, package-lock.json, and go.sum answer that question if anyone reads them. A dependency inventory is not a compliance document; it's the difference between "we should probably update stuff" and "that advisory affects us, here's the file and here's the merged fix."

Run a review of composer outdated --direct, npm outdated, and go list -m all on a schedule. The direct dependencies are where decisions happen. The transitive ones come along for the ride.

The two failure modes

Projects decay in opposite directions, and both look like neglect.

Rot is the familiar one. Nothing gets updated for a year, then a security bug forces an emergency jump across three major versions of a framework, none of which are compatible with each other. The upgrade that would have taken an afternoon in quarterly steps becomes a rewrite-sized project.

Churn is the opposite failure and nobody talks about it. A bot opens automated PRs, someone merges everything with a green checkmark, and next quarter the project has touched ten thousand lines of dependency code it never tested. npm audit shows zero vulnerabilities and the build still doesn't work, because a minor release changed behavior and nobody read the changelog.

Both come from the same root cause: nobody made a decision about which updates matter.

A cadence that works

Split updates into three tiers and treat each differently.

Security patches get pulled forward immediately. A CVE in something on the request path gets a same-day patch and a targeted test. This tier is why the inventory exists; without it you're guessing.

Minor updates get a weekly or biweekly slot. Patch and minor releases with passing CI usually merge fine, but "usually" is doing work in that sentence, so a human skims the changelog first. Lockfiles prevent silent drift between runs; update them deliberately rather than letting an install happen to refresh them.

Major versions get scheduled work, not a bot. Cross-major upgrades touch real code: a Laravel major bumps PHP minimums and changes framework behavior, a Vue major changes reactivity at the core. Block a day, read the upgrade guide, and expect the test suite to earn its keep.

What a green checkmark doesn't tell you

CI passing after an automated upgrade means the code compiles and the existing tests pass. It says nothing about behavior nobody wrote a test for. The changelog skim is not ceremonial; it's where you find "deprecation notice" and "retry logic now re-issues requests by default" before they find you in production.

An update PR in our process mentions what the release changed and why it's safe to merge, in a sentence or two. If the PR author can't write that sentence, the update needs more attention than a merge button.

The quiet deadline: PHP and Node versions themselves

Package updates hide a clock. PHP versions stop receiving security fixes on a published schedule, and Node follows close behind. A Laravel app pinned to an EOL PHP version might have perfectly current packages and still be running a runtime that no longer receives fixes.

When the runtime goes EOL, the upgrade is bigger than a dependency bump. Plan for it in advance instead of discovering it from a hosting provider's warning email.

Making it a habit

A recurring task beats every tool. An hour a week spent on the minor tier plus a same-day habit for security releases keeps a Laravel or Go project permanently updatable. Anything a scheduled task can automate, let an automated tool draft the PR; the human time goes to the changelog and the merge decision, not the mechanics.

The measure that matters is boring: any dependency on the project can move one major version without a rewrite. When that's true, security patches ship the day they're needed, and "we can't update, it's too risky" is a sentence you never have to say to a client.