skip to content

In Ruby with Bundler, what is the difference between `require "bundler/setup"` and `Bundler.require`, and how do group arguments change each?

level: middleimportance: must knowfreq 55%

answer

  1. load path versus actually loading
  2. setup: all groups minus without
  3. require: :default when called bare
  4. Bundler.setup(:test) omits :default
  5. require: option picks the file

basics

~20 s

require "bundler/setup" calls Bundler.setup, which puts the locked gems of all installed groups on the load path but loads none. Bundler.require runs setup and then requires every gem of the named groups, :default when called without arguments.

solid answer

~40 s

`Bundler.setup`, which `require "bundler/setup"` calls, makes the bundle *available*: it checks the Gemfile against Gemfile.lock and the running Ruby, activates the locked version of each gem, adds their `lib` directories to `$LOAD_PATH` and blocks gems outside the bundle. It requires no gem; your code still writes `require "sinatra"`. Without arguments it sets up every group except those skipped by `without`; `Bundler.setup(:default, :test)` restricts it, and `Bundler.setup(:test)` alone omits `:default`. `Bundler.require(*groups)` calls setup for those groups and then **requires** each gem in them, using the gem's `require:` option or its name. Without arguments it requires only `:default`, so frameworks pass groups explicitly, as in `Bundler.require(:default, ENV.fetch("RACK_ENV", "development").to_sym)`. Setup gives explicit control over load order; require trades that for convenience and boot cost.

code

ruby · 6 lines
ruby
# config.ru of a small Rack app
require "bundler/setup"          # locked gems on the load path, none loaded
require "sinatra/base"           # explicit, in the order you choose
require_relative "app"

run App

go deeper

for a junior

Recall that bundler/setup makes the locked gems available and that Bundler.require also loads them, the default group when called without arguments.

for a middle

Explain which groups each call covers by default, why Bundler.setup(:test) leaves out :default, and how the require option decides what Bundler.require loads.

for a senior

Choose explicit requires or Bundler.require per application, controlling boot time and load-order side effects, and debug LoadErrors caused by missing group setup.

for a principal

Decide whether the organisation's services autoload their bundles or require explicitly, weighing boot time, memory per process and how clearly dependencies read in code.

## Two steps: make available, then load Running Ruby code under **Bundler** involves two separate steps: 1. **Setup** - decide which gem versions this process may use and make their files findable. 2. **Require** - actually load a gem's code into the process. `require "bundler/setup"` (or calling `Bundler.setup`) performs only step 1. `Bundler.require` performs step 1 for the requested groups and then step 2 for every gem in them. ## What `Bundler.setup` does When `Bundler.setup` runs, it: - validates the running Ruby and platform against the Gemfile's `ruby` directive and the lockfile, raising `RubyVersionMismatch` on a wrong Ruby; - compares the Gemfile with Gemfile.lock: in frozen mode a mismatch raises, otherwise Bundler re-resolves and writes the updated lockfile; - removes gem paths that were already on the load path from other activations; - activates the **exact locked version** of each gem in the requested groups and adds its `lib` directories to `$LOAD_PATH`; - patches RubyGems so `Kernel#gem` and gem activation cannot reach gems outside the bundle. After that, `require "sinatra"` finds Sinatra's locked version, and `require "some_gem_not_in_the_gemfile"` fails with `LoadError` even if that gem is installed on the machine. Groups decide which gems are set up: ```ruby Bundler.setup # all groups, except those in the without setting Bundler.setup(:default) # only the default group Bundler.setup(:default, :test) # default and test Bundler.setup(:test) # test only - NOT default ``` The call is cached: once a no-argument `Bundler.setup` has run in a process, later calls return immediately. ## What `Bundler.require` does `Bundler.require(*groups)` is `Bundler.setup(*groups)` followed by requiring each dependency whose group matches (and whose platform matches the running Ruby). For every gem it requires: - the paths given by the Gemfile's `require:` option, when present; - nothing, when the option is `require: false`; - otherwise the gem's name, retrying with dashes turned into slashes on a `LoadError` for that path. With **no arguments it requires only `:default`**. That is the most common surprise: gems in a `:test` group are set up by a bare `Bundler.setup`, but a bare `Bundler.require` does not load them. Applications therefore pass the environment's group, as in `Bundler.require(:default, :test)` or a computed list. ## Side by side | | `require "bundler/setup"` | `Bundler.require` | |---|---|---| | Locked versions enforced | yes | yes (runs setup first) | | Default groups | all, minus `without` | `:default` only | | Gems loaded | none | every gem in the named groups | | Load order | yours, explicit | Gemfile order | | Boot cost | only what you require | everything in the groups | ## How the `without` setting interacts A group skipped at install time by the `without` setting is not installed, so a bare `Bundler.setup` leaves it out rather than failing on missing gems. Asking for it explicitly is different: - `Bundler.setup` with no arguments covers the requested groups: all groups, minus `without`, minus optional groups not named in `with`. Skipped groups are simply left out. - Naming a skipped group explicitly, as in `Bundler.setup(:test)` or `Bundler.require(:test)`, asks for gems that were never installed, and setup fails with Bundler reporting them as missing. - Code that never asks for the group and never requires its gems is unaffected. This is why production images that skip `development` and `test` boot fine with a bare setup and fail only if code asks for a test-only group or gem. ## Choosing between them - **Libraries, scripts and small Rack or Sinatra apps** usually call `require "bundler/setup"` and then require what they use. Load order is visible, and gems with load-time side effects are loaded only where intended. - **Frameworks that autoload the whole bundle** call `Bundler.require` with the current environment's groups, and use `require: false` in the Gemfile for gems that must not be loaded eagerly. - **Neither replaces** `require_relative` for your own files; Bundler handles gems only. ## Traps - Calling `Bundler.require(:test)` in a spec helper without an earlier setup of `:default`: only the test group is on the load path. - Expecting `require "bundler/setup"` to load gems; it never does. - Forgetting that `require: false` gems are still set up: an explicit `require` of them works.

  • A spec helper calls `Bundler.require(:test)` first. Why does `require "sinatra"` then fail?
    Because `Bundler.require(:test)` runs `Bundler.setup(:test)`, which sets up only the test group, not `:default`. Sinatra's lib directory never reached the load path. Call `require "bundler/setup"` (all groups) first, or pass both groups: `Bundler.require(:default, :test)`.
  • Can code call `Bundler.require` more than once?
    Yes. Once a no-argument `Bundler.setup` has run, later setup calls return the cached runtime, so `Bundler.require(:default)` at boot and `Bundler.require(:test)` later each just require their group's gems. Bundler's own documentation shows exactly that pattern.

saying these in an interview costs you the question

  • require "bundler/setup" loads every gem in the Gemfile
  • A bare Bundler.require loads the test and development groups too
  • Bundler.setup(:test) also sets up the default group
  • After Bundler.setup, gems outside the Gemfile can still be required if installed
  • Bundler.require skips version checks because it only loads files