mathewboswell.com — automating-dependency-updates-without-breaking-production.md
guest@mathewboswell:~$ cat automating-dependency-updates-without-breaking-production.md

Automating Dependency Updates Without Breaking Production

2024-04-16 · # security # automation # dependencies # devops

Teams usually turn on automated dependency updates with good intentions. A few weeks later, something breaks in production, and the bot gets switched off or its pull requests pile up unreviewed.

The problem is rarely the automation itself. It is the absence of guardrails around what gets updated, how it is tested, and how it reaches production.

Respect version boundaries

Semantic versioning is a promise, not a guarantee, but it is a useful starting point.

  • Patch updates (1.4.2 → 1.4.3) should contain fixes only. These are the best candidates for automation.
  • Minor updates (1.4 → 1.5) add features and may change behavior at the edges.
  • Major updates (1 → 2) are expected to break things.

Configure your tooling to treat these differently. Patch updates can flow quickly. Minor updates can be grouped and reviewed. Major updates should get their own pull request, a changelog review, and an owner.

Some ecosystems and packages don't follow semver closely. Pre-1.0 packages in particular may break on minor bumps. Track which dependencies have a history of surprises and give them stricter rules.

Pin and lock

Lockfiles are what make automated updates safe. They ensure the version you tested is the version you ship. Commit them, make CI fail when they drift, and let the update tool modify them directly.

Avoid wide version ranges for production dependencies. They let new versions appear in builds without a pull request, which defeats the point of reviewing updates.

Tests are the real gate

An automated update is only as safe as the tests it passes. If a repository's tests don't exercise the code that uses a dependency, a green build means very little.

A few practical checks:

  • Does the suite run on every update pull request, including integration tests?
  • Do tests cover the main paths that use each critical dependency?
  • Are there contract or API tests for services that depend on serialization, HTTP clients, or database drivers?

Where coverage is thin, keep auto-merge off for that repository. Investing in a handful of integration tests around heavily used libraries often unlocks more automation than any tool configuration.

Compatibility checks beyond tests

Some breakage won't show up in unit tests:

  • Runtime version requirements. A new release may require a newer language runtime.
  • Transitive conflicts. Two dependencies may want incompatible versions of a shared library.
  • License changes. A new version may change its license.
  • Native components. Packages with compiled extensions can behave differently across platforms.

Add checks for these in CI: runtime compatibility, dependency conflict resolution, and license policy.

Group sensibly

Fifty separate pull requests a week are hard to review. One giant pull request is hard to debug.

Group related updates, such as all packages from the same framework family or all dev-only tooling. Keep security fixes separate so they don't wait behind unrelated changes. Schedule non-security updates for a predictable window so reviewers know when to expect them.

Deploy in rings

Merging an update shouldn't mean every instance gets it at once.

Use deployment rings or progressive delivery:

  1. Internal or staging environment with realistic traffic or synthetic checks
  2. Canary with a small share of production traffic
  3. Broader rollout in stages, with health checks between each

Define in advance which metrics stop the rollout: error rates, latency percentiles, crash counts, or queue depth. Automate the halt.

Plan the rollback before you need it

Every automated update should have an obvious way back. Usually that is reverting the pull request and redeploying, or shifting traffic back to the previous release.

Two things make rollback harder than it looks:

  • Data migrations. If a new library version changes stored formats, reverting code may not revert data. Flag dependencies that touch persistence for manual review.
  • Coupled changes. If an update merged alongside other work, a revert can take more than you intended. Keep update pull requests focused.

Test rollback occasionally. A path nobody has exercised tends to fail at the worst moment.

A starting configuration

For a team turning this on for the first time:

  • Auto-merge patch updates in well-tested repositories after CI passes
  • Group minor updates weekly for human review
  • Open major updates individually with an assigned owner
  • Fast-track security updates outside the schedule
  • Deploy every update through the normal progressive rollout

Then watch the numbers: merge rate, time to merge, failed deployments, and reverts. Expand automation where the data says it is safe.

The goal

Automated dependency updates should feel uneventful. When version boundaries, tests, compatibility checks, rings, and rollback are all in place, they usually are.

guest@mathewboswell:~$ cd /posts
guest@mathewboswell:/posts/automating-dependency-updates-without-breaking-production2026 — System 1.0