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 |