skip to content

In RVM, what is a gemset, how do `rvm use 4.0.7@billing --create` and the `@global` gemset work together, and where do new gems go?

level: middleimportance: nice to knowfreq 22%

answer

  1. named gem directory per Ruby
  2. ruby-4.0.7@billing under ~/.rvm/gems
  3. @global visible to every gemset
  4. --create or 'does not exist' error
  5. .ruby-gemset holds only the name

basics

~20 s

A gemset is a named gem directory attached to one installed Ruby. rvm use 4.0.7@billing --create creates and selects ~/.rvm/gems/ruby-4.0.7@billing; new gems install there, while gems in that Ruby's @global gemset stay visible to it.

solid answer

~40 s

An RVM gemset is a separate gem directory for one Ruby, written `ruby@name`. `rvm use 4.0.7@billing --create` creates `~/.rvm/gems/ruby-4.0.7@billing` if needed and points the shell's gem install directory at it, with the Ruby's `@global` gemset appended to the gem search path. So `gem install` writes into `@billing`, gems in `@global` (by default bundler, rake and RVM's helper gems) are visible to every gemset of that Ruby, and gems in another gemset are invisible. Without `--create`, a missing gemset is an error telling you to create it first. A `.ruby-gemset` file holding just `billing`, next to `.ruby-version`, selects the gemset on `cd`. Since Bundler resolves each project from its lockfile, gemsets are now mostly legacy.

code

bash · 6 lines
bash
rvm use 4.0.7@billing --create   # create + select
rvm current                      # ruby-4.0.7@billing
gem install rake                 # goes into ~/.rvm/gems/ruby-4.0.7@billing
rvm gemset list                  # gemsets of ruby-4.0.7
rvm --ruby-version use 4.0.7@billing
cat .ruby-version .ruby-gemset   # ruby-4.0.7 / billing

go deeper

for a junior

Recall that a gemset is a named gem folder for one Ruby, written ruby@name, and that @global is shared by that Ruby's gemsets.

for a middle

Explain the install directory versus the search path, what --create does, and how .ruby-gemset pairs with .ruby-version.

for a senior

Show you know callers name gemsets explicitly on old servers, and that Bundler's lockfile, not the gemset, decides versions.

for a principal

Judge when gemsets are worth keeping during a migration, and how to retire them without breaking crontabs and service files.

## What a gemset is A **gemset** is RVM's way of giving one installed Ruby several independent gem directories. Each Ruby RVM installs, say `ruby-4.0.7`, gets a **default** gem directory at `~/.rvm/gems/ruby-4.0.7`. A named gemset adds another directory beside it, joined with the gemset separator `@`: `~/.rvm/gems/ruby-4.0.7@billing`. The full environment name `ruby-4.0.7@billing` is what `rvm current` prints. Gemsets were created before Bundler existed, when two applications on one machine needing different versions of the same gem had no other clean way to coexist. The idea is simple: instead of one shared pile of gems per Ruby, each application gets its own pile, and the shell decides which pile is active. ## How selection works When you select a gemset, RVM computes two things for the shell: 1. the **install directory**: the named gemset's directory, so `gem install` writes there; 2. the **search path**: the named gemset first, then the Ruby's `@global` gemset. RVM exports these through the RubyGems environment variables and prepends each directory's `bin` to `PATH`, so executables installed into the gemset are found by the shell. | Selected | Gems install into | Gems visible | |---|---|---| | `rvm use 4.0.7` | `ruby-4.0.7` (default gemset) | default + `@global` | | `rvm use 4.0.7@billing` | `ruby-4.0.7@billing` | `@billing` + `@global` | | `rvm use 4.0.7@global` | `ruby-4.0.7@global` | `@global` only | | `rvm use 4.0.7@billing --ignore-gemsets` | `ruby-4.0.7` | default only | ## The `@global` gemset `@global` is shared by every gemset of the **same** Ruby, never across Rubies. RVM fills it at install time from a `global.gems` list; in RVM master that list holds `gem-wrappers`, `rubygems-bundler`, `rake`, `rvm` and `bundler`. That is why `bundle` works in a brand-new gemset without installing it there. Two consequences to remember: - a gem installed while `@global` is selected appears in every gemset of that Ruby, which can quietly change what an application loads; - `@global` belongs to one Ruby, so upgrading from `ruby-4.0.6` to `ruby-4.0.7` starts with a fresh `@global` and fresh named gemsets; `rvm gemset copy` can carry gems across. ## Creating, listing and removing gemsets - `rvm use 4.0.7@billing --create` creates the gemset if missing and selects it. - Without `--create`, RVM refuses: `Gemset 'billing' does not exist, 'rvm ruby-4.0.7 do rvm gemset create billing' first, or append '--create'.` - `rvm gemset create billing`, `rvm gemset list` and `rvm gemset delete billing` act on gemsets of the current Ruby; `rvm gemset empty` removes every gem from the gemset currently in use, after a confirmation. - `rvm gemset copy 4.0.7@billing 4.0.7@billing-next` copies the gems into another gemset. - `rvm list gemsets` lists every Ruby with its gemsets. - `rvm gemset export` writes the gems of the current gemset to a `billing.gems` file (or `default.gems` with no gemset), and `rvm gemset import` installs such a list into the current gemset. ## Common mistakes - **Treating a gemset as a version pin.** A gemset can hold two versions of the same gem side by side; without Bundler, `require` activates the newest one available on the gem path. - **Assuming gemsets survive a Ruby upgrade.** Gemsets hang off one ruby string, so `ruby-4.0.7@billing` and a later Ruby's `@billing` are unrelated directories until you copy or reinstall the gems. - **Installing tools into `@global` casually.** Whatever lands there is visible to every gemset of that Ruby, so a one-off tool installed there can shadow what an application expects. ## Selecting a gemset per project RVM reads a `.ruby-gemset` file sitting beside `.ruby-version`: `.ruby-version` holds the Ruby (`ruby-4.0.7`) and `.ruby-gemset` holds only the name (`billing`). When the `cd` hook loads these files it creates the gemset if it is missing. `rvm --ruby-version use 4.0.7@billing` writes both files. Other version managers read `.ruby-version` and ignore `.ruby-gemset`. ## Gemsets and Bundler today Bundler isolates a project differently: the Gemfile and its lockfile decide which versions load, and `bundle exec` activates exactly those, whatever else is installed in the gem directory. With that in place, a gemset only keeps the gem directory small and separate; it no longer decides versions. That is why most teams stopped creating gemsets, and why rbenv never had them. You still meet them on older servers, where a deploy user's crontab or a service file names `ruby-4.0.7@billing` explicitly, and removing the gemset without changing those callers breaks them.

  • Why can a gem installed while `@global` is selected break an unrelated application?
    `@global` sits on the gem search path of every gemset of that Ruby. A new or newer gem there becomes visible to every application using any gemset of that Ruby, so code that loads gems without `bundle exec` can pick it up. With Bundler the lockfile still controls what loads, which is one reason teams leaned on Bundler instead of gemsets.
  • What does `--ignore-gemsets` change when you run `rvm use 4.0.7@billing --ignore-gemsets`?
    RVM drops both the named gemset and `@global`, so the shell uses only the Ruby's default gem directory. Setting `rvm_ignore_gemsets_flag=1` in `~/.rvmrc` makes that permanent for users who want per-Ruby gems without gemsets.

saying these in an interview costs you the question

  • Thinks @global is shared across all installed Ruby versions
  • Believes a gemset pins gem versions the way a lockfile does
  • Expects rvm use ruby@name to create a missing gemset without --create
  • Puts ruby-4.0.7@billing into .ruby-gemset instead of just the name
  • Assumes gems in another gemset of the same Ruby are visible