mise: Modern Dev Tools Version Manager
Most developers manage multiple version managers: nvm for Node.js, pyenv for Python, rbenv for Ruby, goenv for Go. Each has separate config files, hooks, and commands. mise (pronounced "meeze", previously rtx) replaces all of them. It's a single Rust-based tool that installs and manages runtime versions for any language, reads .tool-versions files for project consistency, and runs 3-10x faster than asdf (which it's API-compatible with).
Why mise
Single tool for all runtimes: Install Node 20, Python 3.12, Ruby 3.3, and Go 1.22 with one tool and one config file.
Speed: Written in Rust. Activating mise adds ~2ms to shell startup vs 50-100ms for asdf. Installing tools is parallelized.
asdf compatibility: mise reads .tool-versions files (asdf's format). Switch from asdf to mise with no project file changes.
Project-scoped versions: Put a .mise.toml or .tool-versions in your project directory — anyone who clones the repo gets the same tool versions.
Task runner: mise includes a task runner that reads from .mise.toml, eliminating the need for Makefiles for simple project tasks.
Installation
# macOS (Homebrew)
brew install mise
# Linux/macOS (curl installer)
curl https://mise.run | sh
# Cargo
cargo install mise
Add to shell profile:
# bash
echo 'eval "$(mise activate bash)"' >> ~/.bashrc
# zsh
echo 'eval "$(mise activate zsh)"' >> ~/.zshrc
# fish
echo 'mise activate fish | source' >> ~/.config/fish/config.fish
Basic Usage
# Install a specific version
mise install node@20
mise install node@lts
mise install [email protected]
mise install [email protected]
mise install [email protected]
# Set global defaults
mise use --global node@20
mise use --global [email protected]
# Set project-scoped versions (writes to .mise.toml)
cd my-project
mise use node@18
mise use [email protected]
# Check current versions
mise current
# List installed versions
mise list
# Update all tools
mise upgrade
.mise.toml — Project Configuration
mise uses .mise.toml for project configuration:
# .mise.toml
[tools]
node = "20"
python = "3.12"
ruby = "3.3"
go = "1.22"
# Install a specific minor version
terraform = "1.7.0"
# Multiple versions (primary + alternates)
node = ["20", "18"]
[env]
# Environment variables when in this project
DATABASE_URL = "postgres://localhost/myapp_dev"
NODE_ENV = "development"
[tasks.test]
description = "Run tests"
run = "npm test"
[tasks.build]
description = "Build the project"
run = "npm run build"
[tasks.dev]
description = "Start dev server"
run = "npm run dev"
.tool-versions Compatibility
If you're coming from asdf:
# .tool-versions (asdf format — mise reads this too)
nodejs 20.10.0
python 3.12.0
ruby 3.3.0
mise reads both .mise.toml and .tool-versions — no migration required.
Installing Tools (Plugins)
mise uses the same plugin ecosystem as asdf. Most tools are available by default:
# List available tools
mise plugins ls-remote
# Install from the registry
mise install [email protected]
mise install [email protected]
mise install [email protected]
mise install awscli@2
mise install rust@stable
# Install a tool using a URL-based plugin
mise plugin install my-tool https://github.com/org/asdf-my-tool
Task Runner
mise includes a built-in task runner:
# .mise.toml
[tasks.test]
description = "Run the test suite"
run = "pytest tests/ -v"
depends = ["install"]
[tasks.install]
description = "Install dependencies"
run = "pip install -r requirements.txt"
[tasks.lint]
description = "Run linters"
run = [
"flake8 src/",
"mypy src/",
]
[tasks.ci]
description = "Full CI pipeline"
depends = ["install", "lint", "test"]
mise run test
mise run lint
mise run ci
mise tasks # List all tasks
Shell Integration
mise automatically activates the correct versions when you cd into a project:
cd ~/projects/new-app # Uses .mise.toml: node@20
cd ~/projects/legacy-app # Uses .tool-versions: node@14
No manual nvm use or pyenv local needed. mise hooks into your shell's cd command.
Environment Variables
mise can manage per-project environment variables:
[env]
DATABASE_URL = "postgres://localhost/dev"
SECRET_KEY = "dev-secret-key"
Or reference external files (with .mise.toml in .gitignore):
[env]
_.file = ".env"
This replaces direnv for many use cases.
Migration from nvm / pyenv / asdf
From nvm:
# Install mise
curl https://mise.run | sh
# Add to shell profile
echo 'eval "$(mise activate zsh)"' >> ~/.zshrc
# Set global node version
mise use --global node@20
# Remove nvm from shell profile
# Remove ~/.nvm and nvm shell hooks
From asdf: Nothing to change — mise reads your .tool-versions files.
mise vs asdf
| mise | asdf | |
|---|---|---|
| Language | Rust | Bash |
| Shell activation | ~2ms | ~50-100ms |
| Parallel installs | ✓ | ✗ |
| .tool-versions compat | ✓ | ✓ (native) |
| .mise.toml | ✓ | ✗ |
| Task runner | ✓ | ✗ |
| Env variables | ✓ | Via plugin |
| Plugin ecosystem | Same as asdf | Native |
mise vs nvm
nvm is Node.js specific. mise handles Node, Python, Ruby, Go, and 300+ other tools. If you only use Node, nvm works. For polyglot development, mise handles everything.
Shell Prompt Integration
Show active tool versions in your prompt (works with Starship):
# ~/.config/starship.toml
[mise]
format = "[$symbol$version]($style) "
symbol = "mise "
Or use mise current in your prompt script to show active versions.
mise is a substantial quality-of-life improvement for developers working with multiple runtimes and projects. The asdf compatibility makes migration nearly effortless.