Mastering Version Managers: The Complete Guide to nvm, jenv, and gvm
Master the art of managing multiple runtime versions seamlessly with nvm for Node.js, jenv for Java, and gvm for Go. Never struggle with version conflicts again.

Managing multiple versions of programming languages is a challenge every developer faces. Whether you're maintaining legacy projects, testing across different versions, or working on multiple applications simultaneously, version managers are essential tools in your development arsenal. This comprehensive guide walks you through setting up and mastering nvm (Node Version Manager), jenv (Java Environment Manager), and gvm (Go Version Manager).
Why Version Managers Matter
Before diving into setup, let's understand why version managers are indispensable:
Project-Specific Requirements: Different projects often require different language versions. A legacy application might need Node.js 14, while your new project uses Node.js 20.
Testing Across Versions: Ensure compatibility by testing your code against multiple runtime versions without complicated system-wide installations.
Team Consistency: Version managers make it easy to ensure every team member uses the exact same language version, eliminating "works on my machine" scenarios.
Safe Experimentation: Test new language features and versions without affecting your stable development environment.
Part 1: Setting Up nvm (Node Version Manager)
Node Version Manager is the most popular tool for managing multiple Node.js installations. It's fast, reliable, and incredibly easy to use.
Installing nvm
On Linux/macOS/WSL:
# Download and install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# Or using wget
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
The installation script automatically adds nvm to your shell profile (~/.bashrc, ~/.zshrc, or ~/.profile).
Activate nvm immediately:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
Verify installation:
nvm --version
# Output: 0.39.7
Using nvm: Essential Commands
Install the latest LTS version:
nvm install --lts
Install a specific version:
nvm install 18.19.0
nvm install 20.11.0
nvm install 16.20.2
List installed versions:
nvm ls
# Output shows all installed versions with the current one marked
Switch between versions:
nvm use 18.19.0
# Now using node v18.19.0
nvm use 20
# Automatically uses the latest v20.x installed
Set a default version:
nvm alias default 20.11.0
# This version loads when you open a new terminal
Check current version:
node --version
# v20.11.0
Pro nvm Tips
Project-specific Node version with .nvmrc:
Create a .nvmrc file in your project root:
echo "18.19.0" > .nvmrc
Now anyone can use the correct version:
cd your-project
nvm use
# Found '.nvmrc' with version <18.19.0>
# Now using node v18.19.0
Automatic version switching (optional):
Add to your ~/.zshrc or ~/.bashrc:
# Automatically switch Node version when entering a directory with .nvmrc
autoload -U add-zsh-hook
load-nvmrc() {
local node_version="$(nvm version)"
local nvmrc_path="$(nvm_find_nvmrc)"
if [ -n "$nvmrc_path" ]; then
local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")
if [ "$nvmrc_node_version" = "N/A" ]; then
nvm install
elif [ "$nvmrc_node_version" != "$node_version" ]; then
nvm use
fi
elif [ "$node_version" != "$(nvm version default)" ]; then
nvm use default
fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc
Migrate global packages:
When switching versions, migrate your global npm packages:
nvm install 20 --reinstall-packages-from=18
Uninstall a version:
nvm uninstall 16.20.2
Part 2: Setting Up jenv (Java Environment Manager)
jenv allows you to manage multiple Java installations seamlessly, perfect for projects requiring different JDK versions.
Installing jenv
On macOS with Homebrew:
brew install jenv
On Linux/WSL:
git clone https://github.com/jenv/jenv.git ~/.jenv
Configure your shell:
For Bash (~/.bashrc):
export PATH="$HOME/.jenv/bin:$PATH"
eval "$(jenv init -)"
For Zsh (~/.zshrc):
export PATH="$HOME/.jenv/bin:$PATH"
eval "$(jenv init -)"
Reload your shell:
exec $SHELL -l
Verify installation:
jenv --version
# jenv 0.5.x
Installing Java JDKs
Before using jenv, you need Java installations. Here's how to install multiple versions:
On Ubuntu/Debian:
# Install OpenJDK 11
sudo apt install openjdk-11-jdk
# Install OpenJDK 17
sudo apt install openjdk-17-jdk
# Install OpenJDK 21
sudo apt install openjdk-21-jdk
On macOS:
# Install via Homebrew
brew install openjdk@11
brew install openjdk@17
brew install openjdk@21
Configuring jenv
Add Java versions to jenv:
# On Linux
jenv add /usr/lib/jvm/java-11-openjdk-amd64
jenv add /usr/lib/jvm/java-17-openjdk-amd64
jenv add /usr/lib/jvm/java-21-openjdk-amd64
# On macOS (Homebrew installations)
jenv add /usr/local/opt/openjdk@11
jenv add /usr/local/opt/openjdk@17
jenv add /usr/local/opt/openjdk@21
List managed versions:
jenv versions
# Output:
# system
# * 17.0 (set by /home/user/.jenv/version)
# 11.0
# 21.0
Using jenv: Essential Commands
Set global Java version:
jenv global 17.0
Set local (project-specific) version:
cd your-java-project
jenv local 11.0
# Creates .java-version file
Set shell-specific version:
jenv shell 21.0
# Affects only current shell session
Verify current Java version:
java -version
# openjdk version "17.0.x"
Pro jenv Tips
Enable plugins for better functionality:
# Enable export plugin (sets JAVA_HOME automatically)
jenv enable-plugin export
# Enable maven plugin
jenv enable-plugin maven
# Enable gradle plugin
jenv enable-plugin gradle
List available plugins:
jenv plugins
Check which Java jenv is using:
jenv which java
# Shows full path to java executable
Part 3: Setting Up gvm (Go Version Manager)
gvm makes managing multiple Go versions effortless, essential for Go developers working across different projects.
Installing gvm
Prerequisites:
# On Ubuntu/Debian
sudo apt-get install curl git mercurial make binutils bison gcc build-essential
# On macOS
xcode-select --install
brew install mercurial
Install gvm:
bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
Source gvm in your shell:
The installer automatically adds gvm to your shell profile. Reload it:
source ~/.gvm/scripts/gvm
Verify installation:
gvm version
# Go Version Manager v1.0.x
Using gvm: Essential Commands
List available Go versions:
gvm listall
# Shows all available Go versions
Install a Go version:
# Install Go 1.21 (requires existing Go or binary bootstrap)
gvm install go1.21.5 -B
# Install Go 1.22
gvm install go1.22.0 -B
The -B flag uses pre-compiled binaries (faster and simpler).
List installed versions:
gvm list
# Shows all installed Go versions
Switch to a version:
gvm use go1.21.5
# Now using version go1.21.5
# Set as default
gvm use go1.21.5 --default
Verify current version:
go version
# go version go1.21.5 linux/amd64
Pro gvm Tips
Create isolated Go environments (pkgsets):
# Create a package set for a specific project
gvm pkgset create myproject
# Use the package set
gvm pkgset use myproject
# List package sets
gvm pkgset list
Package sets isolate dependencies, similar to Python virtual environments.
Uninstall a Go version:
gvm uninstall go1.20.0
Update gvm itself:
gvm get
Real-World Workflows
Scenario 1: Full-Stack Developer
You're working on multiple projects:
# Project A: Legacy Node.js app
cd project-a
echo "14.21.3" > .nvmrc
nvm use
npm install
# Project B: Modern React app
cd ../project-b
echo "20.11.0" > .nvmrc
nvm use
npm install
# Project C: Java microservice
cd ../project-c
jenv local 17.0
./mvnw spring-boot:run
# Project D: Go CLI tool
cd ../project-d
gvm use go1.22.0
go build
Scenario 2: CI/CD Integration
.github/workflows/node-ci.yml:
name: Node CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
Scenario 3: Team Onboarding
Project README.md:
## Setup
1. Install nvm: [instructions]
2. Install correct Node version:
\`\`\`bash
nvm install
nvm use
\`\`\`
3. Install dependencies:
\`\`\`bash
npm install
\`\`\`
Troubleshooting Common Issues
nvm: command not found
Solution: Source nvm in your current shell:
source ~/.nvm/nvm.sh
Make sure the nvm initialization is in your shell profile.
jenv: JAVA_HOME not set
Solution: Enable the export plugin:
jenv enable-plugin export
exec $SHELL -l
gvm: cannot install Go version
Solution: Use binary installation:
gvm install go1.22.0 -B
Slow shell startup with version managers
Solution: Use lazy loading. Add to ~/.zshrc:
# Lazy load nvm
export NVM_DIR="$HOME/.nvm"
nvm() {
unset -f nvm
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
nvm "$@"
}
Best Practices
1. Always Use .nvmrc / .java-version Files
Document required versions in your project:
# .nvmrc
18.19.0
# .java-version
17.0
2. Document Version Requirements
Update your README.md:
## Requirements
- Node.js 18.x (managed via nvm)
- Java 17 (managed via jenv)
- Go 1.21+ (managed via gvm)
3. Don't Commit node_modules or Build Artifacts
Your .gitignore:
node_modules/
.nvmrc
.java-version
target/
dist/
4. Keep Version Managers Updated
# Update nvm
cd "$NVM_DIR" && git pull && cd -
# Update gvm
gvm get
5. Use CI/CD Version Matrices
Test against multiple versions automatically to catch compatibility issues early.
Conclusion
Version managers—nvm, jenv, and gvm—are essential tools that eliminate version conflicts, streamline team collaboration, and enable seamless multi-project development. By mastering these tools, you can:
- Switch between project environments instantly
- Test across multiple runtime versions effortlessly
- Onboard new team members in minutes
- Maintain legacy and modern projects simultaneously
Start with nvm if you're primarily a JavaScript developer, add jenv for Java projects, and incorporate gvm for Go development. Each tool follows similar patterns, making it easy to adopt additional version managers as your tech stack grows.
At Arion Interactive, we leverage these version managers across our development teams to ensure consistent, reproducible builds and seamless collaboration. Ready to modernize your development workflow? Let's build something amazing together!