CrackedRuby logo

CrackedRuby

rbenv

Complete guide to rbenv for managing multiple Ruby versions in development and production environments.

Overview

rbenv manages multiple Ruby installations on a single system through version-specific directory structures and executable shims. The tool intercepts Ruby commands and routes them to the appropriate version based on project-specific configuration files or global settings.

The core architecture relies on three main components: the rbenv executable that handles version switching, shims that proxy Ruby commands to the correct installation, and plugins that extend functionality for installing and managing Ruby versions. rbenv modifies the system PATH to prioritize its shim directory, ensuring Ruby commands execute through rbenv's version resolution system.

rbenv determines which Ruby version to use through a precedence hierarchy. It first checks for a .ruby-version file in the current directory and parent directories, then examines the global version file, and finally falls back to the system Ruby installation. This approach enables per-project version management without requiring manual PATH manipulation.

# Create project-specific version file
File.write('.ruby-version', '3.2.0')

# rbenv reads this file to determine active Ruby version
system('ruby --version')
# => ruby 3.2.0p0 (2022-12-25 revision a528908681)

The shim mechanism creates lightweight wrapper scripts for Ruby executables. When Ruby commands execute, rbenv intercepts the call, determines the appropriate version, and delegates to the real executable in that version's installation directory.

# Shim structure example
$ which ruby
/Users/developer/.rbenv/shims/ruby

$ rbenv which ruby
/Users/developer/.rbenv/versions/3.2.0/bin/ruby

rbenv integrates with shell environments through initialization scripts that modify PATH and define shell functions. The initialization process creates the shim directory precedence and enables the rbenv command with tab completion and shell integration features.

Basic Usage

Installing rbenv requires cloning the repository and adding initialization to shell configuration. The installation process sets up the directory structure and modifies the shell environment to prioritize rbenv shims.

# Clone rbenv repository
git clone https://github.com/rbenv/rbenv.git ~/.rbenv

# Add to PATH and initialize
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc

The rbenv install command manages Ruby version installations through the ruby-build plugin. Each Ruby version installs to a separate directory under ~/.rbenv/versions/, maintaining complete isolation between versions.

# List available Ruby versions
rbenv install --list | grep -E "^\s*3\."

# Install specific version
rbenv install 3.2.0

# Install with specific build options
RUBY_CONFIGURE_OPTS="--with-openssl-dir=/usr/local/opt/openssl" rbenv install 3.1.4

Setting Ruby versions operates at global and local scopes. Global settings affect all projects without local configuration, while local settings apply only to the current project directory and subdirectories.

# Set global Ruby version
rbenv global 3.2.0

# Set local Ruby version for current project
rbenv local 2.7.8

# Check current active version
rbenv version
# => 2.7.8 (set by /path/to/project/.ruby-version)

The shim regeneration process updates executable wrappers when installing or removing Ruby versions or gems with executables. rbenv automatically triggers rehashing in most scenarios, but manual rehashing resolves shim inconsistencies.

# Regenerate shims after gem installation
rbenv rehash

# List installed Ruby versions
rbenv versions
#   system
# * 2.7.8 (set by /path/to/project/.ruby-version)
#   3.1.4
#   3.2.0

# Remove specific version
rbenv uninstall 2.7.8

Project workflow typically involves setting a local Ruby version and installing dependencies. The .ruby-version file contains only the version number and should be committed to version control for team consistency.

# Initialize project with specific Ruby version
cd new-project
rbenv local 3.2.0
bundle init
bundle install

# Verify configuration
cat .ruby-version
# => 3.2.0

rbenv exec ruby -v
# => ruby 3.2.0p0 (2022-12-25 revision a528908681)

The rbenv exec command explicitly executes commands with the determined Ruby version, bypassing potential PATH complications and ensuring the correct Ruby environment.

Error Handling & Debugging

rbenv installation failures commonly stem from missing system dependencies required for compiling Ruby. The ruby-build plugin requires development tools, libraries, and headers that vary across operating systems.

# Debug installation with verbose output
rbenv install --verbose 3.2.0

# Check system dependencies on Ubuntu/Debian
sudo apt-get install -y build-essential libreadline-dev libssl-dev zlib1g-dev

# Check system dependencies on macOS
xcode-select --install
brew install openssl readline

PATH configuration issues manifest when rbenv commands work but Ruby commands use system versions. This indicates incomplete shell initialization or conflicting PATH entries that override rbenv shims.

# Diagnose PATH configuration
echo $PATH | grep rbenv
# Should show: /Users/developer/.rbenv/shims:/Users/developer/.rbenv/bin

# Check rbenv initialization
rbenv doctor
# Runs comprehensive environment diagnostics

# Verify shim directory precedence
which ruby
# Should point to: ~/.rbenv/shims/ruby

Shim inconsistencies occur when gem installations add new executables but rbenv doesn't automatically regenerate shims. This results in command not found errors for recently installed gem executables.

# Install gem with executable
gem install rails

# Error: command not found
rails --version

# Solution: regenerate shims
rbenv rehash

# Verify new shim creation
ls ~/.rbenv/shims/ | grep rails
# => rails

Version resolution debugging involves understanding rbenv's precedence hierarchy. The rbenv version command shows the active version and configuration source, while rbenv versions displays all installed versions.

# Debug version resolution
rbenv version
# => 2.7.8 (set by /path/to/project/.ruby-version)

# Check version file hierarchy
rbenv version-file
# => /path/to/project/.ruby-version

# Override version temporarily
RBENV_VERSION=3.2.0 ruby --version
# => ruby 3.2.0p0 (2022-12-25 revision a528908681)

Build failures during Ruby installation require examining build logs and addressing missing dependencies. Common issues include SSL library mismatches, missing development headers, and compiler incompatibilities.

# Examine build logs
tail -f ~/.rbenv/versions/3.2.0/build.log

# Common SSL library fix on macOS
RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl@1.1)" rbenv install 3.2.0

# Force clean installation
rbenv uninstall 3.2.0
rbenv install 3.2.0

Shell integration problems manifest when rbenv commands execute but don't affect the Ruby environment. This indicates the shell isn't loading rbenv initialization or competing Ruby version managers interfere.

# Test rbenv integration in Ruby
system('rbenv version')

# Check if rbenv functions are available
if ENV['RBENV_VERSION']
  puts "rbenv active: #{ENV['RBENV_VERSION']}"
else
  puts "rbenv not controlling Ruby version"
end

Permission errors during installation typically result from attempting to install to system directories or running rbenv with elevated privileges. rbenv operates entirely within user directories and should never require sudo.

# Correct: user-based installation
rbenv install 3.2.0

# Incorrect: system-wide installation attempt
sudo rbenv install 3.2.0  # DON'T DO THIS

# Fix permission issues
chown -R $(whoami) ~/.rbenv

Production Patterns

Production rbenv deployments require careful consideration of user permissions, installation consistency, and deployment automation. Applications typically specify Ruby versions through .ruby-version files that deployment processes must respect.

Deployment scripts automate rbenv installation and Ruby version management across environments. The installation process includes system dependency verification, rbenv setup, and Ruby compilation with production-optimized build flags.

#!/bin/bash
# Production rbenv deployment script

# Install system dependencies
apt-get update && apt-get install -y \
  build-essential libreadline-dev libssl-dev \
  zlib1g-dev libyaml-dev libffi-dev

# Install rbenv for deployment user
export RBENV_ROOT=/opt/rbenv
git clone https://github.com/rbenv/rbenv.git $RBENV_ROOT
git clone https://github.com/rbenv/ruby-build.git $RBENV_ROOT/plugins/ruby-build

# Set up environment
export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"

# Install Ruby version from project specification
RUBY_VERSION=$(cat .ruby-version)
RUBY_CONFIGURE_OPTS="--disable-install-doc --with-jemalloc" rbenv install $RUBY_VERSION
rbenv global $RUBY_VERSION

Container environments require rbenv installation during image building rather than runtime initialization. The container approach involves baking Ruby versions into images and using rbenv for version selection during application startup.

FROM ubuntu:22.04

# Install rbenv and dependencies
RUN apt-get update && apt-get install -y \
    git curl build-essential libreadline-dev \
    libssl-dev zlib1g-dev libyaml-dev libffi-dev

RUN git clone https://github.com/rbenv/rbenv.git /usr/local/rbenv
RUN git clone https://github.com/rbenv/ruby-build.git /usr/local/rbenv/plugins/ruby-build

ENV PATH="/usr/local/rbenv/bin:/usr/local/rbenv/shims:$PATH"
ENV RBENV_ROOT="/usr/local/rbenv"

# Pre-install common Ruby versions
RUN rbenv install 2.7.8 && rbenv install 3.1.4 && rbenv install 3.2.0
RUN rbenv global 3.2.0 && rbenv rehash

Service management with rbenv requires careful environment variable configuration and process isolation. Services must inherit the correct PATH and RBENV_ROOT settings to execute Ruby applications with the appropriate version.

# systemd service configuration for rbenv-managed application
# /etc/systemd/system/myapp.service

[Unit]
Description=My Ruby Application
After=network.target

[Service]
Type=simple
User=deploy
WorkingDirectory=/opt/myapp
Environment=RBENV_ROOT=/opt/rbenv
Environment=PATH=/opt/rbenv/bin:/opt/rbenv/shims:/usr/local/bin:/bin:/usr/bin
ExecStart=/opt/rbenv/shims/bundle exec puma -C config/puma.rb
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Application servers require rbenv integration through process managers or direct execution wrappers. The configuration ensures applications start with the correct Ruby version and maintain consistency across processes.

# Capistrano deployment integration
# config/deploy.rb

set :rbenv_type, :user
set :rbenv_ruby, File.read('.ruby-version').strip
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w{rake gem bundle ruby rails puma sidekiq}

# Custom rbenv initialization task
namespace :rbenv do
  task :validate do
    on roles(:app) do
      rbenv_ruby_version = capture("#{fetch(:rbenv_path)}/bin/rbenv version").strip
      unless rbenv_ruby_version.include?(fetch(:rbenv_ruby))
        raise "Ruby version mismatch: expected #{fetch(:rbenv_ruby)}, got #{rbenv_ruby_version}"
      end
    end
  end
end

Monitoring rbenv installations involves tracking Ruby version consistency, shim availability, and build failures. Automated checks verify that deployments use specified Ruby versions and rbenv remains properly configured.

#!/usr/bin/env ruby
# rbenv health check script

def check_rbenv_health
  checks = {
    rbenv_installed: system('which rbenv > /dev/null 2>&1'),
    ruby_version_matches: check_ruby_version_consistency,
    shims_current: check_shim_currency,
    global_version_set: !`rbenv global`.strip.empty?
  }
  
  checks.each do |check, result|
    status = result ? '' : ''
    puts "#{status} #{check}"
  end
  
  exit(1) unless checks.values.all?
end

def check_ruby_version_consistency
  expected = File.read('.ruby-version').strip rescue nil
  current = `rbenv version`.split.first
  expected == current
end

def check_shim_currency
  gem_executables = `find ~/.rbenv/versions/*/lib/ruby/gems/*/bin -name "*" -type f 2>/dev/null`.lines.map { |line| File.basename(line.strip) }.uniq
  shim_executables = Dir.glob('~/.rbenv/shims/*').map { |file| File.basename(file) }
  (gem_executables - shim_executables).empty?
end

check_rbenv_health

Migration & Compatibility

Ruby version migrations through rbenv require careful planning for application compatibility and dependency management. Applications must verify compatibility with target Ruby versions before migration and update dependencies accordingly.

Version compatibility testing involves creating isolated environments for each Ruby version and running comprehensive test suites. The process identifies compatibility issues early and provides confidence in migration decisions.

# Test application against multiple Ruby versions
for version in 2.7.8 3.1.4 3.2.0; do
  echo "Testing with Ruby $version"
  rbenv local $version
  bundle install --quiet
  
  if bundle exec rspec; then
    echo "✓ Ruby $version: All tests pass"
  else
    echo "✗ Ruby $version: Test failures detected"
    bundle exec rspec --format documentation --fail-fast
  fi
done

# Restore original version
rbenv local --unset

Dependency compatibility requires analyzing gem compatibility matrices and updating Gemfiles for Ruby version requirements. Some gems require specific Ruby versions or have compatibility constraints that affect migration timing.

# Gemfile version constraints for migration
source 'https://rubygems.org'

ruby '>= 2.7.0', '< 4.0'  # Specify Ruby version range

# Version-specific gem requirements
if RUBY_VERSION >= '3.0'
  gem 'psych', '~> 5.0'
else
  gem 'psych', '~> 4.0'
end

# Migration-friendly gem specification
gem 'rails', '~> 7.0.0'  # Compatible with Ruby 2.7-3.2
gem 'puma', '~> 6.0'      # Ruby 3.x optimized

group :development, :test do
  gem 'debug', '>= 1.0.0'  # Ruby 2.7+ debugging
end

Production migration strategies involve blue-green deployments or gradual rollouts that minimize risk. The approach requires maintaining multiple Ruby versions temporarily and validating application behavior before full cutover.

#!/bin/bash
# Production Ruby version migration script

OLD_VERSION="2.7.8"
NEW_VERSION="3.2.0"
APP_PATH="/opt/myapp"

# Pre-migration validation
cd $APP_PATH
rbenv install $NEW_VERSION

# Create migration test environment
rbenv local $NEW_VERSION
bundle install
bundle exec rake assets:precompile RAILS_ENV=production

# Run migration tests
if bundle exec rspec spec/integration/; then
  echo "Migration tests passed for Ruby $NEW_VERSION"
else
  echo "Migration tests failed, aborting migration"
  rbenv local $OLD_VERSION
  exit 1
fi

# Backup current deployment
cp -r $APP_PATH ${APP_PATH}_backup_$(date +%Y%m%d)

# Update production configuration
rbenv global $NEW_VERSION
systemctl restart myapp
sleep 30

# Verify application health
if curl -f http://localhost:3000/health; then
  echo "Migration to Ruby $NEW_VERSION completed successfully"
  rbenv uninstall $OLD_VERSION
else
  echo "Application unhealthy, rolling back"
  rbenv global $OLD_VERSION
  systemctl restart myapp
  exit 1
fi

Legacy Ruby version support requires maintaining older rbenv installations and managing compatibility constraints. Long-term support involves freezing rbenv versions and creating isolated environments for legacy applications.

# Legacy rbenv environment setup
export RBENV_ROOT=/opt/rbenv-legacy
git clone --branch v1.1.2 https://github.com/rbenv/rbenv.git $RBENV_ROOT
git clone https://github.com/rbenv/ruby-build.git $RBENV_ROOT/plugins/ruby-build

# Install legacy Ruby versions with compatibility patches
RUBY_CONFIGURE_OPTS="--with-openssl-dir=/usr/local/ssl" $RBENV_ROOT/bin/rbenv install 2.3.8
RUBY_CONFIGURE_OPTS="--enable-shared" $RBENV_ROOT/bin/rbenv install 2.4.10

# Create wrapper script for legacy environments
cat > /usr/local/bin/rbenv-legacy << 'EOF'
#!/bin/bash
export RBENV_ROOT=/opt/rbenv-legacy
export PATH="$RBENV_ROOT/bin:$PATH"
eval "$($RBENV_ROOT/bin/rbenv init -)"
exec "$@"
EOF

Version pinning strategies balance flexibility with stability. Applications specify exact Ruby versions for reproducible builds while allowing minor version updates for security patches.

# Version pinning in .ruby-version
# Exact version pinning
echo "3.2.0" > .ruby-version

# Minor version flexibility (managed outside rbenv)
# Use automation to update to latest patch level
LATEST_PATCH=$(rbenv install --list | grep "^\s*3\.2\." | tail -1 | tr -d ' ')
echo $LATEST_PATCH > .ruby-version
rbenv install $LATEST_PATCH

Common Pitfalls

Shell initialization order creates common rbenv malfunctions when other version managers or PATH modifications interfere. The initialization sequence must place rbenv early in the PATH and avoid conflicts with system Ruby managers.

# Problematic: rbenv initialization after other version managers
export PATH="/usr/local/bin:$PATH"  # System Ruby first
source ~/.rvm/scripts/rvm           # RVM interference
eval "$(rbenv init -)"              # rbenv too late

# Correct: rbenv initialization priority
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
export PATH="/usr/local/bin:$PATH"  # System paths after rbenv

Multiple version manager conflicts arise when RVM, rbenv, or asdf coexist on the same system. Each manager modifies PATH and shell functions, creating unpredictable version resolution and command routing.

# Detect version manager conflicts
which -a ruby
# Problem: Shows multiple Ruby installations
# /home/user/.rbenv/shims/ruby
# /home/user/.rvm/rubies/ruby-3.0.0/bin/ruby
# /usr/bin/ruby

# Clean removal of conflicting managers
# Remove RVM completely
rvm implode
rm -rf ~/.rvm ~/.rvmrc

# Remove system Ruby version managers
sudo apt-get remove --purge ruby ruby-dev

Shim directory permissions cause execution failures when rbenv installations occur with mixed user permissions or sudo commands. All rbenv operations must maintain consistent user ownership throughout the directory structure.

# Problem: Mixed permissions from sudo usage
ls -la ~/.rbenv/shims/
# -rwxr-xr-x root root ruby
# -rwxr-xr-x user user rails

# Solution: Fix ownership recursively
chown -R $(whoami):$(id -gn) ~/.rbenv
chmod -R u+w ~/.rbenv

# Verify shim execution
~/.rbenv/shims/ruby --version

Environment variable persistence issues occur when rbenv modifications don't survive shell restarts or session changes. The problem indicates incomplete shell profile configuration or conflicts with system-wide environment settings.

# Test environment persistence
# Terminal 1
rbenv local 3.2.0
ruby --version  # => ruby 3.2.0

# Terminal 2 (new session)
ruby --version  # Problem: wrong version

# Diagnose profile loading
echo 'echo "Loading .bashrc"' >> ~/.bashrc
echo 'echo "rbenv PATH: $PATH"' >> ~/.bashrc

# Check profile execution order
ls -la ~/.bash_profile ~/.bashrc ~/.profile
# Ensure rbenv initialization in correct profile

Build compilation failures frustrate developers when system dependencies are incomplete or incompatible. The compilation process requires specific library versions and development headers that vary across operating systems and distributions.

# Comprehensive dependency installation for Ubuntu
sudo apt-get update && sudo apt-get install -y \
  autoconf bison build-essential libssl-dev \
  libyaml-dev libreadline6-dev zlib1g-dev \
  libncurses5-dev libffi-dev libgdbm6 \
  libgdbm-dev libdb-dev uuid-dev

# macOS dependency management
brew install openssl readline libyaml libffi
export RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl) --with-readline-dir=$(brew --prefix readline)"
rbenv install 3.2.0

Global version confusion occurs when developers expect local .ruby-version files to override global settings but encounter unexpected version resolution. Understanding rbenv's precedence hierarchy prevents version selection surprises.

# Debug version resolution with Ruby script
def diagnose_rbenv_version
  puts "Current directory: #{Dir.pwd}"
  puts "Active Ruby: #{RUBY_VERSION}"
  puts "rbenv version: #{`rbenv version`.strip}"
  puts "rbenv version-file: #{`rbenv version-file 2>/dev/null`.strip}"
  
  # Walk directory tree for .ruby-version files
  current = Dir.pwd
  while current != '/'
    version_file = File.join(current, '.ruby-version')
    if File.exist?(version_file)
      puts ".ruby-version found: #{current}/#{version_file} => #{File.read(version_file).strip}"
    end
    current = File.dirname(current)
  end
  
  puts "Global version: #{`rbenv global`.strip}"
end

diagnose_rbenv_version

Rehashing automation failures cause gem executable unavailability after installations. While rbenv automatically rehashes in most scenarios, certain edge cases require manual intervention or automated rehashing in deployment scripts.

# Automated rehashing in gem installation scripts
#!/bin/bash
install_gems_with_rehash() {
  local gems=("$@")
  
  for gem in "${gems[@]}"; do
    echo "Installing $gem..."
    gem install "$gem" --no-document
    
    # Force rehash after each installation
    rbenv rehash
    
    # Verify shim creation
    if ! command -v "$gem" >/dev/null 2>&1; then
      echo "Warning: $gem executable not found after installation"
      rbenv rehash  # Retry rehashing
    fi
  done
}

install_gems_with_rehash rails puma sidekiq

Reference

Core Commands

Command Parameters Returns Description
rbenv install <version> version string exit status Install specific Ruby version
rbenv uninstall <version> version string exit status Remove Ruby version
rbenv versions none version list List all installed versions
rbenv global <version> version string exit status Set global Ruby version
rbenv local <version> version string exit status Set local project version
rbenv version none active version Show current active version
rbenv which <command> executable name file path Show path to executable
rbenv exec <command> command with args command output Execute command with rbenv Ruby
rbenv rehash none exit status Regenerate shim executables
rbenv prefix <version> version string directory path Show version installation directory

Version Resolution Hierarchy

Priority Source Configuration File Scope
1 Environment RBENV_VERSION Current shell session
2 Local .ruby-version Current directory tree
3 Global ~/.rbenv/version User account
4 System /usr/bin/ruby System-wide fallback

Build Configuration Options

Variable Purpose Example Value
RUBY_CONFIGURE_OPTS Ruby build configuration --with-openssl-dir=/usr/local/opt/openssl
MAKE_OPTS Make parallel compilation -j 4
RUBY_BUILD_CACHE_PATH Source code cache directory ~/.rbenv/cache
RUBY_BUILD_BUILD_PATH Temporary build directory /tmp/ruby-build.XXXXXX
RUBY_BUILD_DEFINITIONS Custom definition directory ~/.rbenv/plugins/ruby-build/share/ruby-build

Environment Variables

Variable Description Default Value
RBENV_ROOT rbenv installation directory ~/.rbenv
RBENV_VERSION Force specific Ruby version none
RBENV_DIR Directory for version resolution current directory
RBENV_HOOK_PATH Plugin hook directories $RBENV_ROOT/rbenv.d
RBENV_DEBUG Enable debug output none

Installation Options

Option Effect Use Case
--list Show available versions Version discovery
--list-all Show all versions including old Legacy compatibility
--verbose Show compilation output Build debugging
--keep Preserve source and build files Build inspection
--patch Apply patch during build Custom Ruby modifications

Shim Directory Structure

~/.rbenv/
├── bin/rbenv              # Main rbenv executable
├── shims/                 # Executable proxies
│   ├── ruby
│   ├── gem
│   ├── bundle
│   └── rails
├── versions/              # Ruby installations
│   ├── 2.7.8/
│   ├── 3.1.4/
│   └── 3.2.0/
└── version               # Global version file

Common Error Codes

Exit Code Meaning Resolution
0 Success Continue normally
1 General error Check command syntax and permissions
126 Command invoked cannot execute Verify file permissions and PATH
127 Command not found Run rbenv rehash or check installation
2 Misuse of shell builtins Review command arguments

Plugin System

Plugin Purpose Installation
ruby-build Ruby version installation git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
rbenv-gemset Gemset management git clone git://github.com/jf/rbenv-gemset.git ~/.rbenv/plugins/rbenv-gemset
rbenv-vars Environment variables git clone https://github.com/rbenv/rbenv-vars.git ~/.rbenv/plugins/rbenv-vars
rbenv-default-gems Auto-install gems git clone https://github.com/rbenv/rbenv-default-gems.git ~/.rbenv/plugins/rbenv-default-gems