JT Book a call

Blog

Manage Bundler indirect dependencies versions

Published

3 min read

Manage Bundler indirect dependencies versions
In this post

Have you seen that bundler stuck on finding how to upgrade your gems? What to do if there is a new breaking version of the indirect dependency, causing deployment fails? Bundler looks for options

Sometimes we got broken deploy, because of the not supported version of the gem, and it has been used automatically as an indirect dependency.

Or bundler could find any upgrade because of conflict of the indirect dependencies.

So what can we do? How could we help bundler find better versions for indirect dependencies?

Migrate from indirect to direct dependency status #

Yep, that’s all. We just need to add indirect dependency as direct. And do not forget to add a notice comment to ensure that this gem is required only for assigning version constraints. Add direct dependency to add constraint for indirect

With explicit version constraints assigned for indirect (and now direct) dependency, the bundler will have to satisfy them and will change other gems.

A small example you can run #

rack-test depends on rack (>= 1.3), so with nothing else in the Gemfile, Bundler takes the newest rack it can find. In a fresh bundle lock we got rack 3.2.7. Say your app isn’t ready for Rack 3. Make rack a direct dependency with the limit you need:

gem "rack-test"

# Indirect dependency of rack-test. Listed only to cap its version.
gem "rack", "< 3", require: false

Run bundle lock again and Bundler picks rack 2.2.24, the newest version under 3. rack (< 3) now also shows up in the DEPENDENCIES section of Gemfile.lock, so everyone on the team resolves the same way.

How to see who pulls a gem in #

Open Gemfile.lock and search for the gem name. In the specs section it is listed, indented, under every gem that depends on it, along with the version range that gem asks for:

    rack-test (2.3.0)
      rack (>= 1.3)

That range is what you are narrowing. Pick a limit that still fits inside it, or Bundler has no version left to choose.

Requiring and removing the pin #

Add require: false. A Rails app calls Bundler.require in config/application.rb, which requires the gems from your Gemfile at boot unless you say otherwise. The Gemfile docs show require: false for exactly that. A gem you only list for its version shouldn’t change what loads.

Plan to remove the pin. The comment tells the next developer why the line exists and when it can go, for example once your server supports the newer version. Without it, nobody knows whether the pin is still needed, and it stays.

A softer option: bundle update --conservative #

If the problem is that updating one gem drags its dependencies along, you may not need a pin at all. bundle update --conservative updates the gem you name and leaves its indirect dependencies alone (bundle update docs). Starting from a lock with rack-test 2.1.0 and rack 2.2.24:

bundle update rack-test                 # rack-test 2.3.0, rack 3.2.7
bundle update --conservative rack-test  # rack-test 2.3.0, rack 2.2.24

The pin is still the right tool when a fresh install or a deploy picks a version that breaks you, because --conservative only applies to that one update.

Read next

Tell us what you need built

JetThoughts has been building software since 2008. Book a call, or write to sales@jetthoughts.com. You'll leave the call with a written one-page scope within 2 working days.

#01 Paul Keen
Paul KeenFounder & Open Source Contributor

A 30-minute call; pick a time.