Every couple of weeks, I hear someone complaining about some difficulties with Bundler. Yesterday, it happened twice. But somehow I just never have those difficulties. I'm not saying Bundler is perfect; certainly in its early days it wasn't even close. But for the past two years it's been incredibly solid and trouble-free for me, and I think a large part of the reason is the way I use it. Bundler arguably does too much, and just as with Git, a big part of it is knowing what not to do, and configuring things to avoid the trouble spots.
This is my strategy for using Bundler, and for me it's always been smooth sailing. Give it a try.
First, the quick summary:
bundle config path .bundlefrom your home directory1 2
bundle installin all of your projects
- Always run
bundle update) unless you're explicitly upgrading gem versions.
- Optionally, stop using gemsets.
The rest of this section is a longer version, explaining the rationale.
(This is essentially the same as the "Recommended Workflow" in the bundler-update man page, but not as terse.
If you like terse, go type
bundle help update instead.)
Step 1: Configuring Bundler
Right now, run
bundle config path .bundle from your home directory.1 2
This adds a line to your user-global bundler configuration file (
The effect is that
bundle install will always run as if you'd specified the
--path .bundle option.
What does that do?
It tells Bundler not to install gems in your default gem repository (whether that's a gemset or not);
rather, Bundler will create a project-specific gem repository in the
.bundle directory and manage gems there.
This is an example of what Bundler calls "remembered option"—it's a sticky setting.
Bundler remembers that you asked for a project-specific gem repository for this project,
so any future bundler commands in the project will automatically operate within
Step 2: Updating projects to obey the new configuration
Now go run
bundle install in all of your projects.
Step 3: How to handle Gemfile changes
(Well, almost never ... see below.)
Instead, whenever you update the Gemfile, or when Bundler tells you a gem is not found, just type
What's the difference?
bundle update ignores
It looks at all of the project's gems and updates them to the latest, supposedly greatest versions
that are compatible with the specified version constraints and that satisfy all of the transitive dependencies,
and then regenerates
Even if the project has carefully locked down all of the Gem versions in
this can result in upgrading some of those gems' dependencies,
which is both a nuisance
(because now everyone on the project has to go through a more time-consuming update of multiple gems)
and dangerous (because it will happen in production as well, and one of those upgrades could break something).
bundle is the same as
bundle install, which honors
The job of
bundle install is simply to make the smallest number of changes necessary to make everything consistent.
That means first resolving any changes you made to
and making the minimal necessary changes to
Gemfile.lock to reflect those changes.
Then it installs, upgrades, or removes any gems necessary to make your project gem repo match what's specified in
If you're the one who made the change to the Gemfile, you'll need to run
bundle install, if you prefer being explicit).3 But if someone else made the change and you just pulled it down, you can run
bundle --local. The gems will all be cached in
vendor/cache within the project, and
bundle --local simply uses the cached files and avoids the time-consuming calls to rubygems.org and other gem sources. If in doubt, you can just run
bundle --local; if the right gems aren't in
vendor/cache it will fail quickly, and then you can run the more time-consuming
Step 4: Consider abandoning gemsets
Now, if you'd like, you can stop using gemsets and get rid of all of them. I recommend that you give it a try.
How do you do that, when every project's
.rvmrc file instructs RVM to create and use a gemset?
I did it by switching to rbenv (and I didn't install rbenv's gemset plugin).
If you want to stick to RVM, do this:
echo "export rvm_ignore_gemsets_flag=1" >> ~/.rvmrc
and then exit your shell and restart (or whatever it is you do to get RVM to reload its configuration).
You don't have to stop using gemsets. If you do just the first three steps, but decide to continue using gemsets for your own purposes, that's great and things will work fine. But if your big reason for using gemsets had to do with managing bundler, or keeping project dependencies separate, you don't need them anymore.
A clean separation between "the project's gems" and "my gems" is a big win.
This way, when you install some gem-based programming tool (such as Nick's "jsonpretty" or Evan's "gx") it's useful everywhere, not just in the projects where you've remembered to install it. Of course, you will have to install it for the different Ruby versions you use.
And that also means we can get rid of stuff like this snippet from the Gemfile of one of our projects:
# dev utilities %w[ cheat foreman hirb lunchy open_gem ruby-debug ruby-prof wirble yard ].each do |name| gem name end
At least some of those gems are developer preferences, not project dependencies.
If you like the "cheat", "hirb", and "open_gem" gems, they should be available everywhere on your system,
not just in the gemset for that project.
gem install them!
Finally, and most importantly, Bundler will behave better for you.
You will have to use
bundle exec for things like rake and resque-web,
but you should have been doing that anyway.
I'm not just being pedantic when I say that.
If you were able to run those commands without
you were just getting lucky, and some flaky, strange things were probably happening.
Sooner or later, it would fail in confusing ways.4
There are multiple ways to make
bundle exec easier.
I use a smart Bash function that wraps certain commands and figures out what to do.
Alternatively, you can use Bundler's binstubs (which is a whole 'nuther article).
One more thing: above, I said you should almost never run
But clearly, we do have to update gems, and we should do it fairly regularly,
because it's easier to upgrade if you follow along,
as opposed to lagging behind and then someday being forced to upgrade from a seriously out-of-date gem.
So what should you do?
If you lock down your
Gemfile to explicit versions,
you can just update the version of a selected gem in
Gemfile and then run
That will make the smallest number of upgrades necessary to bring that gem to the requested version.
Then you can test and, if all seems well, commit and deploy.
My preferred method is to not lock things down too tightly in
Then, when I want to try upgrading a gem (let's use the "chronic" gem as an example)
bundle update chronic.
Bundler will update just that gem to the latest version.
(It might have to also update some of chronic's dependencies, but that will be true in either case.)
Then, if testing doesn't uncover any problems, I can commit and deploy.
This method, by the way, only works if nobody on the team ever uses
bundle update except when explicitly trying to upgrade out-of-date gems.
But that's the right way to use it anyway, and it's easy to catch and recover from mistakes.
In either method, you only upgrade gems when you choose to.
Both of these methods update
so the production system and all of your colleagues will end up with the exact same mix of versions you tested with.
(A quick note, thanks to Mark McSpadden:
if you ever accidentally type
bundle install something instead of
bundle update something,
Bundler will install all of your gems in a directory called "something"
and reset things so that that's your project gem repository.
bundle install something is an old, deprecated syntax for
bundle install --path something.
If this happens, just remove the new
something directory, type
bundle install --path .bundle,
and you're back in business, having lost nothing but a bit of time.
Just try not to accidentally type
bundle install app.)
Backing Out of a Gem Upgrade
What if something goes wrong?
The upgrade might break something that didn't show up in your testing.
If that happens, simply check out the most recent versions of
that were working correctly, run
bundle, and deploy.
You'll be back to the exact same gem version mix that was working before.
Note that simply reverting the commit where you upgraded gems will have the desired effect.
If you find problems right away, before committing the changes, just do
git checkout Gemfile Gemfile.lock && bundle
and you'll be in good shape.
1 RubyMine (4.0.x) doesn't see
.bundle and will nag you about missing gems and won't allow you to browse the source of them. If you use RubyMine, instead of
.bundle you'll need to use a directory name that doesn't start with a dot, such as
gems (or perhaps
zzgems to force search hits to the bottom of the results). If you do this, be sure to add
.gitignore in your home directory, so you don't accidentally check your bundle in.
2 If you are a frequent user of ack, you may now start seeing search results from your gems. If you'd like to avoid seeing this output, add
export ACK_OPTIONS=--ignore-dir=.bundle to your bash config file. Happy ACKing!
3 When I'm getting started with a new project, I always type
but then for the rest of the life of that project I type
bundle, even though they do the same thing.
Because, based on the description I just gave of what
bundle install does,
I think it's misnamed, and so using
bundle install for minor updates messes with my mental model.
I know the two ways of invoking the "install" subcommand do the same thing,
but using them differently in those two distinct circumstances just feels right to me.
4 Just last week (as of 2013-08-16) a colleague said "I always thought of bundle exec as a hack ... as in, 'Oh, gems are messed up, just run bundle exec'". The truth is that if you aren't running
bundle exec, gems are always messed up; you're just not seeing visible symptoms. Using the strategy recommended here (especially if you go all the way and abandon gemsets) ensures that if you aren't using
bundle exec things will fail fast, rather than seeming to work and hiding the problems.