In this article, I’ll compare the most popular version managers for Ruby on a Mac: Chruby, Rbenv, and RVM, as well as Asdf, a version manager for multiple languages, and Frum, a brand new version manager written in Rust. I’ll make recommendations based on what you’re most likely to need.
Pre-installed Ruby is Not for Developers
Folks who are new to Ruby are delighted to discover that Ruby comes pre-installed on macOS. They’re often disappointed when a more experienced developer tells them, “Don’t use the Mac system Ruby.” I’ve written elsewhere about the reasons. In short, the system Ruby is there for macOS, not for you. It’s fine for running utility scripts, but for development, the system Ruby is out of date and, if you’re not careful, installation of gems can lead to headaches (including system security violations).
Homebrew’s One Ruby Problem
Homebrew is the package manager that has become a near-standard for adding developer software to macOS. Homebrew makes it easy to install a new Ruby version to avoid relying on the system Ruby. But there are two problems with Homebrew. First, Homebrew’s Ruby version can be automatically and unexpectedly replaced by a newer version when other Homebrew packages are installed (a problem solved by
brew pin ruby). More importantly, Homebrew only lets you install one version of Ruby. If you’re developing or maintaining more than one project in Ruby, you’ll likely need to switch among Ruby versions. That’s where you’ll need a version manager.
Asdf for Multiple Languages
Asdf is a version manager that accommodates multiple languages. If you’re using Ruby to develop web applications with Rails 6, you’ll need to install Node and Yarn to build a Rails starter application. (Rails 7 may eliminate the need for Node, but that’s not yet certain at this time.)
So, for a Rails developer, Asdf is an ideal version manager. It will also serve you well if you develop applications in Python, Elixir, or many other languages (see a list of supported languages). Is there a downside to using Asdf? Just two. It uses shims to intercept common commands, which can make troubleshooting difficult. Also, it can be a little slow for some operations. If you’re developing in multiple languages, I recommend you try Asdf to see if you like it. Switch to Frum, the Ruby-only version manager written in Rust, if you find Asdf slows you down.
Ruby-only Version Managers
If you only intend to develop applications using Ruby, choose among the four Ruby-only version managers: Chruby, Frum, Rbenv, and RVM. Differences among the four lie in speed, complexity, and how each switches Ruby versions. Let’s look at the oldest first: RVM.
RVM was the first popular version manager for Ruby. It’s still maintained and widely used. RVM modifies the system
cd command to set environment variables when you change directories. To override the
cd command, the RVM installation script changes the shell configuration file (the
~/.zshrc file on newer Macs).
RVM properly displays environment variables to reveal the Ruby and gem version and location, which can help diagnose problems. However, RVM includes additional features such as gemsets. Gemsets are no longer needed, since Bundler was added to the core Ruby to manage gem dependencies. The additional complexity isn’t needed, so many developers have switched to a newer version manager such as Rbenv, Chruby, or Frum.
After installing Rbenv with Homebrew, you must modify your
~/.zshrc file so the Rbenv shims take precedence over ordinary Ruby commands. The shim calls the
rbenv exec command, which determines which version of Ruby to use before running any Ruby command.
Shims have two drawbacks. First, shims make troubleshooting more difficult by hiding the actual command. For example, the
which ruby command shows the Rbenv shim, not the actual Ruby version (you must set the
RBENV_DEBUG environment variable if you want to see the actual Ruby command). Second, a shim can add microseconds of delay to execution of a Ruby command. (Rbenv intervenes every time you run a Ruby command unlike RVM, which intervenes only when you change directories.) For developers who notice the delay, or don’t like the idea of shims, there is Chruby or Frum.
Chruby is not as well-known as RVM or Rbenv, but it’s championed by several prominent Ruby developers. Unlike RVM, it doesn’t override the
cd command. Unlike Rbenv or Asdf, it doesn’t intercept commands using shims. You’ll need to modify your
~/.zshrc file so Chruby runs in your local shell environment. There’s no need to modify your
$PATH, as Chruby does that for you, based on the Ruby version you’ve selected.
Chruby also sets certain environment variables for Ruby. That’s all that’s needed for Chruby to switch among Ruby versions. It works fine for troubleshooting with
which. I used Chruby for several years and had no problems with it. Chruby is a great choice, but you may want to try Frum, the newest Ruby version manager.
Frum is written in Rust, a good language for fast command-line execution of system software. Frum is new (released in early 2021). Unlike Asdf, Chruby, or Rbenv, it includes a built-in Ruby installer command so there’s no extra program needed to install Ruby. The installer is fast, and Frum requires no dependencies (it’s an all-in-one Rust executable you can install with Homebrew).
After you install Frum, you must modify your
~/.zshrc file so Frum runs in your local shell environment. Like the other version managers, it checks for a
.ruby-version file in a project directory and, if there’s no version specified for a project, it will default to a global Ruby version. There are no shims (unlike Asdf or Rbenv) and it doesn’t override the
cd command (unlike RVM). Though it’s new, I recommend it because it’s all-in-one and fast.
Installing a Version Manager for Ruby
I’ve written a complete guide to installing Ruby on Mac. In the guide, I provide instructions for:
- installing Ruby with Asdf
- installing Ruby with Frum
- installing Ruby with Chruby
- installing Ruby with Homebrew
If you want to explore RVM or Rbenv, see:
A Note about Docker
If you mention Ruby version managers, someone will likely say, “I use Docker.” Docker is a containerization tool that some developers use for version management. The primary use case for Docker is to create a reproducible virtual server that contains a configured version of any software dependency needed to run an application (language, databases, message queues). As such, it’s ideal for creating a “frozen” version of a development environment for deployment to a server.
You can also develop locally within a container, but it will run slower, require more memory, and add configuration complexity compared to a version manager. To keep things simple, I avoid Docker for local development unless an application is disturbingly complex.
You’re not just a casual Ruby user if you’re working on multiple projects in Ruby. Make sure you install a great version manager in your local development environment.
which command. If these drawbacks outweigh the convenience of managing multiple languages, I recommend using Frum to switch among your Ruby versions. Version managers should be simple and stay out of your way when you’re working.