Version Managers Complete Guide: nvm, pyenv, rbenv, jenv & More

Managing multiple versions of programming languages is essential for modern development. Whether you're maintaining legacy projects, testing across versions, or just want the latest features, version managers make this process seamless.
In this comprehensive guide, we'll cover version managers for all major languages: Node.js, Python, Ruby, Java, Go, Rust, and more.
Why Use Version Managers?
The Problem Without Version Managers
Scenario: You have three projects:
- Project A: Requires Node.js 14 (legacy)
- Project B: Uses Node.js 18 (stable)
- Project C: Needs Node.js 20 (bleeding edge)
Without version manager:
# Manually install Node 14
sudo apt install nodejs=14.x
cd project-a && npm install
# Uninstall Node 14, install Node 18
sudo apt remove nodejs
sudo apt install nodejs=18.x
cd project-b && npm install
# Repeat for Node 20...
# š± This is painful!With version manager (nvm):
nvm install 14 18 20
cd project-a && nvm use 14
cd project-b && nvm use 18
cd project-c && nvm use 20
# š Effortless!Benefits of Version Managers
ā
Multiple versions simultaneously - Switch instantly between versions
ā
Per-project versions - .nvmrc, .python-version files auto-switch
ā
No sudo required - User-level installations
ā
Easy cleanup - Remove versions with one command
ā
Reproducible environments - Same versions across team members
ā
Testing across versions - Validate compatibility easily
Node.js Version Managers
Option 1: nvm (Node Version Manager)
Most popular choice for Node.js version management.
Installation
macOS/Linux:
# Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# Or with wget
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# Add to shell profile (~/.bashrc, ~/.zshrc)
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
# Reload shell
source ~/.zshrc # or ~/.bashrcWindows: Use nvm-windows:
# Download installer from GitHub releases
# Run nvm-setup.exeUsage
# List available Node versions
nvm ls-remote
# Install specific version
nvm install 20.10.0
nvm install 18.19.0
nvm install 14.21.3
# Install latest LTS
nvm install --lts
# List installed versions
nvm ls
# Use specific version
nvm use 20.10.0
# Set default version
nvm alias default 20.10.0
# Run command with specific version
nvm exec 18.19.0 node app.js
# Uninstall version
nvm uninstall 14.21.3Per-Project Version with .nvmrc
Create .nvmrc in project root:
20.10.0Then:
cd my-project
nvm use # Automatically uses version from .nvmrcAuto-switch with shell hook:
# Add to ~/.zshrc or ~/.bashrc
autoload -U add-zsh-hook
load-nvmrc() {
if [[ -f .nvmrc && -r .nvmrc ]]; then
nvm use
fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrcPros & Cons
Pros:
- ā Most popular and well-maintained
- ā Simple shell script (no compilation)
- ā Cross-platform (with nvm-windows)
- ā Large community support
Cons:
- ā Slow startup time (shell script overhead)
- ā Not native on Windows
Option 2: fnm (Fast Node Manager)
Rust-based alternative to nvm, much faster.
Installation
# macOS/Linux
curl -fsSL https://fnm.vercel.app/install | bash
# macOS with Homebrew
brew install fnm
# Windows with Chocolatey
choco install fnm
# Add to shell profile
eval "$(fnm env --use-on-cd)"Usage
# List remote versions
fnm ls-remote
# Install version
fnm install 20.10.0
# Use version
fnm use 20.10.0
# Set default
fnm default 20.10.0
# Auto-use .nvmrc or .node-version
fnm usePros & Cons
Pros:
- ā 20x faster than nvm
- ā Cross-platform (native Windows support)
- ā
Compatible with
.nvmrcfiles - ā Built-in shell integration
Cons:
- ā Less mature than nvm
- ā Smaller community
Recommendation: Use fnm for speed, nvm for stability.
Python Version Managers
Option 1: pyenv
De facto standard for Python version management.
Installation
macOS:
# Install dependencies
brew install openssl readline sqlite3 xz zlib
# Install pyenv
brew install pyenv
# Add to shell profile
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init --path)"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
source ~/.zshrcLinux:
# Install dependencies (Ubuntu/Debian)
sudo apt update
sudo apt install -y make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev \
libffi-dev liblzma-dev
# Install pyenv
curl https://pyenv.run | bash
# Add to ~/.bashrc
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"Windows: Use pyenv-win:
Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"Usage
# List available Python versions
pyenv install --list
# Install specific version
pyenv install 3.12.1
pyenv install 3.11.7
pyenv install 3.10.13
# List installed versions
pyenv versions
# Set global Python version
pyenv global 3.12.1
# Set local (per-directory) version
cd my-project
pyenv local 3.11.7 # Creates .python-version file
# Set shell session version
pyenv shell 3.10.13
# Uninstall version
pyenv uninstall 3.10.13Virtual Environments with pyenv-virtualenv
# Install plugin
brew install pyenv-virtualenv # macOS
# Or clone manually
git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
# Add to shell profile
eval "$(pyenv virtualenv-init -)"
# Create virtual environment
pyenv virtualenv 3.12.1 my-project-env
# Activate
pyenv activate my-project-env
# Deactivate
pyenv deactivate
# Auto-activate per directory
cd my-project
pyenv local my-project-env # Auto-activates when entering directoryPros & Cons
Pros:
- ā Industry standard for Python
- ā Integrates with virtualenv
- ā
.python-versionfile support - ā Compiles Python from source (optimized)
Cons:
- ā Requires compilation (slow installs)
- ā Many system dependencies
Option 2: asdf with Python Plugin
Unified version manager for multiple languages.
# Install asdf
brew install asdf # macOS
# Or git clone https://github.com/asdf-vm/asdf.git ~/.asdf
# Add Python plugin
asdf plugin add python
# Install Python
asdf install python 3.12.1
# Set version
asdf global python 3.12.1
asdf local python 3.11.7Ruby Version Managers
Option 1: rbenv
Simple and Unix-like Ruby version manager.
Installation
# macOS
brew install rbenv ruby-build
# Linux (Ubuntu)
sudo apt install rbenv
# Or install via Git
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
# Add to shell profile
echo 'eval "$(rbenv init - zsh)"' >> ~/.zshrc
source ~/.zshrcUsage
# List available Ruby versions
rbenv install --list
# Install Ruby
rbenv install 3.3.0
rbenv install 3.2.2
# List installed versions
rbenv versions
# Set global version
rbenv global 3.3.0
# Set local (per-directory) version
rbenv local 3.2.2 # Creates .ruby-version
# Rehash shims (after installing gems)
rbenv rehash
# Uninstall
rbenv uninstall 3.2.2Pros & Cons
Pros:
- ā Lightweight and simple
- ā No magic (just shims)
- ā Fast
Cons:
- ā Manual rehashing sometimes needed
- ā No gemset management (use bundler instead)
Option 2: rvm (Ruby Version Manager)
Feature-rich alternative with gemsets.
# Install
\curl -sSL https://get.rvm.io | bash -s stable
# Install Ruby
rvm install 3.3.0
# Use version
rvm use 3.3.0
# Create gemset
rvm gemset create my-project
rvm use 3.3.0@my-projectRecommendation: Use rbenv for simplicity, rvm for gemsets.
Java Version Managers
Option 1: jenv
Java version manager similar to rbenv.
Installation
# macOS
brew install jenv
# Add to shell profile
echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(jenv init -)"' >> ~/.zshrc
source ~/.zshrcUsage
# Add Java installations
jenv add /Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home
jenv add /Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home
jenv add /Library/Java/JavaVirtualMachines/jdk-11.jdk/Contents/Home
# List versions
jenv versions
# Set global version
jenv global 21
# Set local version
jenv local 17 # Creates .java-version
# Enable Maven/Gradle integration
jenv enable-plugin maven
jenv enable-plugin gradleNote: jenv doesn't install Java; it only manages existing installations.
Option 2: SDKMAN!
Comprehensive Java ecosystem manager.
Installation
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"Usage
# List Java versions
sdk list java
# Install Java
sdk install java 21.0.1-tem # Temurin (AdoptOpenJDK)
sdk install java 17.0.9-amzn # Amazon Corretto
sdk install java 11.0.21-zulu # Azul Zulu
# Use version
sdk use java 21.0.1-tem
# Set default
sdk default java 21.0.1-tem
# Install other tools
sdk install gradle
sdk install maven
sdk install kotlin
sdk install scalaPros & Cons
jenv Pros:
- ā Lightweight
- ā Simple
SDKMAN! Pros:
- ā Installs Java for you
- ā Manages Gradle, Maven, Kotlin, Scala
- ā Multiple JDK vendors
Recommendation: Use SDKMAN! for full ecosystem management.
Go Version Manager: gvm
# Install
bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
# Install Go version
gvm install go1.21.5
# Use version
gvm use go1.21.5
# Set default
gvm use go1.21.5 --defaultAlternative: Just download binaries from go.dev and update PATH.
Rust Version Manager: rustup
Official Rust toolchain installer.
# Install rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install toolchains
rustup toolchain install stable
rustup toolchain install beta
rustup toolchain install nightly
# Set default
rustup default stable
# Use specific version
rustup override set nightly # For current directory
# Update Rust
rustup updateasdf: Universal Version Manager
One tool to rule them all.
Installation
# macOS
brew install asdf
# Linux
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.14.0
# Add to shell profile
echo '. "$HOME/.asdf/asdf.sh"' >> ~/.zshrc
echo '. "$HOME/.asdf/completions/asdf.bash"' >> ~/.zshrc
source ~/.zshrcUsage
# Add plugins
asdf plugin add nodejs
asdf plugin add python
asdf plugin add ruby
asdf plugin add java
asdf plugin add golang
# Install versions
asdf install nodejs 20.10.0
asdf install python 3.12.1
asdf install ruby 3.3.0
# Set global versions
asdf global nodejs 20.10.0
asdf global python 3.12.1
# Set local versions
asdf local nodejs 18.19.0 # Creates .tool-versions file
# List all plugins
asdf plugin list all.tool-versions File
nodejs 20.10.0
python 3.12.1
ruby 3.3.0Pros & Cons
Pros:
- ā One tool for all languages
- ā Consistent interface
- ā
Single
.tool-versionsfile
Cons:
- ā Plugin quality varies
- ā Less language-specific features than dedicated tools
Comparison Table
| Language | Recommended Tool | Alternative | Notes |
|---|---|---|---|
| Node.js | fnm | nvm | fnm is 20x faster |
| Python | pyenv | asdf | pyenv has better virtualenv support |
| Ruby | rbenv | rvm | rbenv is simpler, rvm has gemsets |
| Java | SDKMAN! | jenv | SDKMAN! installs Java for you |
| Go | Official binaries | gvm | Go's backward compatibility is good |
| Rust | rustup | - | Official tool, use it |
| Multi-language | asdf | - | Best for polyglot projects |
Best Practices
1. Use Version Files
Always commit version files to Git:
# .nvmrc (Node.js)
20.10.0
# .python-version (Python)
3.12.1
# .ruby-version (Ruby)
3.3.0
# .tool-versions (asdf)
nodejs 20.10.0
python 3.12.1
ruby 3.3.02. Document in README
## Prerequisites
- Node.js 20.10.0 (use `nvm install`)
- Python 3.12.1 (use `pyenv install 3.12.1`)3. CI/CD Integration
GitHub Actions with nvm:
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'GitHub Actions with pyenv:
- uses: actions/setup-python@v5
with:
python-version-file: '.python-version'4. Team Consistency
# Setup script for new team members
#!/bin/bash
nvm install
pyenv install
bundle install
npm install5. Avoid Global Installs
# ā BAD
npm install -g typescript
# ā
GOOD (per-project)
npm install --save-dev typescript
npx tscCommon Workflows
Workflow 1: Testing Multiple Python Versions
# Install versions
pyenv install 3.12.1 3.11.7 3.10.13
# Test script
for version in 3.12.1 3.11.7 3.10.13; do
pyenv shell $version
python --version
python -m pytest
doneWorkflow 2: Project Onboarding
# New developer setup
cd project
nvm use # Reads .nvmrc
pyenv install # Reads .python-version
npm install
pip install -r requirements.txtWorkflow 3: Upgrade Path
# Current: Node 18 ā Target: Node 20
nvm install 20.10.0
nvm use 20.10.0
npm install
npm test # Verify compatibility
# Update .nvmrc
echo "20.10.0" > .nvmrcTroubleshooting
Issue 1: "command not found: nvm"
Cause: Shell profile not sourced.
Fix:
# Add to ~/.zshrc or ~/.bashrc
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
source ~/.zshrcIssue 2: pyenv build fails
Cause: Missing system dependencies.
Fix (Ubuntu):
sudo apt install -y make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev \
libffi-dev liblzma-devIssue 3: Slow shell startup with nvm
Cause: nvm is a shell script.
Fix: Use lazy loading:
# Add to ~/.zshrc
export NVM_DIR="$HOME/.nvm"
nvm() {
unset -f nvm
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm "$@"
}Or switch to fnm (much faster).
Issue 4: jenv doesn't change Java version
Cause: JAVA_HOME not exported.
Fix:
jenv enable-plugin exportSummary and Key Takeaways
ā
Version managers enable seamless multi-version development
ā
Node.js: Use fnm (fast) or nvm (stable)
ā
Python: Use pyenv with pyenv-virtualenv
ā
Ruby: Use rbenv (simple) or rvm (feature-rich)
ā
Java: Use SDKMAN! for ecosystem management
ā
Rust: Use rustup (official tool)
ā
Multi-language: Use asdf for consistency
ā
Commit version files (.nvmrc, .python-version, .tool-versions)
ā
Document versions in README for team onboarding
ā
CI/CD integration with version file support
What's Next?
Now that you can manage multiple runtime versions, explore:
Development Tools:
- Docker for containerized development environments
- Dev Containers (VS Code) for reproducible setups
- Nix for declarative environment management
Related Topics:
- Package managers (npm, pip, bundler, cargo)
- Virtual environments and isolation
- CI/CD best practices
Additional Resources
Official Documentation:
Tools:
Have questions about version managers or need help with setup? Leave a comment below!
Happy version managing! š
š¬ Subscribe to Newsletter
Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.
We respect your privacy. Unsubscribe at any time.
š¬ Comments
Sign in to leave a comment
We'll never post without your permission.