Moving to mise: A Developer's Guide to Simplifying Version Management

Fahmi Aulia Rahman 8 min read

TL;DR

nah fr, juggling multiple version managers like nvm, rbenv, gvm, and brew for different languages is actual pain. I switched to mise and it’s been a game changer - one CLI to manage ALL my runtime versions (Node.js, Ruby, Go, Python, you name it). It’s blazing fast, clean, and has way less mental overhead. Here’s why you should make the switch too.

The Pain Was Real

Let’s be honest - before mise, my dev setup was lowkey chaotic:

  • nvm for Node.js
  • rbenv for Ruby
  • gvm for Go
  • pyenv for Python
  • brew for PHP and other random tools

Each had their own commands, config files, and weird quirks. My shell took forever to load because of all the version managers sourcing their scripts. Plus, keeping track of different syntax across tools? That hits different when you’re context switching between projects.

Enter mise: The One Tool to Rule Them All

mise is basically a universal version manager. Instead of managing separate tools, you get one consistent interface for everything. Think of it as the npm/yarn of version managers, but written in Rust so it’s incredibly fast.

Key Benefits That Actually Matter

  1. Single CLI interface - no more remembering if it’s nvm use or rbenv local
  2. One config file (.tool-versions or mise.toml) per project
  3. Way better performance - zero startup overhead, it modifies PATH directly
  4. Universal support - supports Node.js, Ruby, Go, Python, PHP, Java, and basically anything else

Migration Made Easy

From nvm (Node.js)

If you’re coming from nvm, the migration is pretty straightforward:

Old way:

# .nvmrc
18.17.0

New way:

# .tool-versions
node 18.17.0

From rbenv (Ruby)

Old way:

# .ruby-version
3.2.0

New way:

# .tool-versions
ruby 3.2.0

From gvm (Go)

Old way:

gvm use go1.20 --default

New way:

# .tool-versions
go 1.20.0

The best part? mise can read legacy version files (.nvmrc, .ruby-version, etc.) automatically. This means you can migrate gradually without breaking existing projects.

Essential Commands You’ll Actually Use

Here are the commands I use daily (no cap, these are the ones that matter):

Version Installation

# See available versions
mise list-remote node
mise list-remote ruby

# Install specific version
mise use [email protected]
mise use [email protected]

# Install from .tool-versions file
mise install  # installs all tools defined in current dir

Setting Versions

# Set global version
mise use -g [email protected]

# Set project version in this directory
mise use [email protected]

Checking Current Setup

# See current versions
mise current

# See what's installed locally
mise ls

# Check where tool is installed
mise where [email protected]

The Magic config files

This is where mise really shines. One file to define all your project’s runtime requirements. You can use the standard .tool-versions:

# .tool-versions
node 18.17.0
ruby 3.2.0
go 1.20.0
python 3.11.0

Or the more powerful mise.toml:

[tools]
node = "18.17.0"
ruby = "3.2.0"
go = "1.20.0"

When you cd into a project directory, mise automatically activates these versions. No more forgetting to switch environments!

Pro Tips That’ll Save You Time

1. Task Running

mise isn’t just for versions. It can run tasks too, replacing npm scripts or Makefile in many cases:

# mise.toml
[tasks]
build = "npm run build"
test = "go test ./..."

Run with mise run build.

2. Environment Variables

You can set project-specific env vars in mise.toml:

[env]
NODE_ENV = "development"
API_URL = "http://localhost:3000"

3. Global Tools

Need a tool everywhere?

mise use -g ripgrep

4. Run Tools Without Switching Context

Need to run a command with a specific tool version without installing it globally or modifying your shell context? This is perfect for maintaining legacy systems (e.g., an old Node.js project):

# Run npm run dev using Node 10 without switching your current node version
mise x node@10 -- npm run dev

5. Architecture Support

On Apple Silicon but need to run an Intel (x86_64) binary? You can force the architecture in your mise.toml:

[env]
# Force architecture for tools in this project
MISE_ARCH = "x86_64"

Why This Actually Matters

Beyond the obvious convenience, mise solves real problems:

Team Synchronization: Everyone runs the exact same versions defined in configuration. No more “works on my machine” issues.

Performance: It’s written in Rust and extremely fast. It barely touches your shell startup time compared to other tools.

Context Switching: Jump between projects without thinking about version management. It just works.

Mental Load Reduction: One syntax to rule them all. Less cognitive overhead = more focus on actual coding.

The Verdict

Look, I’m not trying to be dramatic, but switching to mise was genuinely one of those “why didn’t I do this sooner” moments. The setup takes like 10 minutes, and then you never have to think about version management complexity again.

If you’re still juggling multiple version managers in 2025, you’re making your life harder than it needs to be. mise is the modern, fast, and unified way to handle your dev environment.

Give it a try. I guarantee you won’t go back to the old fragmented approach. Your future self (and your teammates) will thank you.

Summary

What we covered:

  • Why multiple version managers are pain
  • How mise simplifies everything with one tool
  • Easy migration from nvm, rbenv, gvm, etc.
  • Essential commands you’ll actually use
  • Real setup instructions that work
  • Pro tips including task running, legacy execution, and env vars

Key takeaway: mise eliminates the complexity of managing multiple version managers while providing incredible performance and team consistency. It’s 2025 - time to upgrade your workflow.

About the author

Portrait of Fahmi Aulia Rahman

Fahmi Aulia Rahman

Software Engineer

Software engineer with 6+ years under the hood with new dad vibes — shipping cool stuff, learning out loud and keeping it real.