mise — Dev Tools Version Manager
What is mise?
mise (pronounced “meez”, as in mise en place) is a fast, polyglot development tool version manager. It replaces a fragmented collection of language-specific version managers — nvm for Node.js, pyenv for Python, rbenv for Ruby, goenv for Go, sdkman for Java — with a single unified tool that manages all of them.
mise reads a .mise.toml (or .tool-versions) configuration file and automatically activates the right versions of your tools depending on which directory you are in. This makes it trivial to work on multiple projects that require different language versions without any manual switching.
Originally a rewrite and extension of asdf, mise is significantly faster, written in Rust, and adds powerful features like task running, environment variable management, and a richer configuration system.
Why Use mise?
- One tool, all languages — manage Node, Python, Ruby, Go, Java, Rust, Deno, Bun, and hundreds more.
- Per-project versions —
.mise.tomlin a project root automatically activates the right versions. - Fast — written in Rust; tool activations are nearly instant.
- Task runner — define project tasks in
.mise.tomland run them withmise run. - Environment variables — set env vars per project or per directory.
- Compatible with
.tool-versions— drop-in replacement forasdf. - Plugin ecosystem — install tools via
asdfplugins ormise’s built-in backends.
Installation
# macOS (Homebrew)
brew install mise
# Linux / macOS (install script — installs to ~/.local/bin/mise)
curl https://mise.run | sh
# Windows (PowerShell)
winget install jdx.mise
# Arch Linux (AUR)
yay -S mise-bin
# After installation, activate mise in your shell:
# For bash — add to ~/.bashrc
echo 'eval "$(mise activate bash)"' >> ~/.bashrc
source ~/.bashrc
# For zsh — add to ~/.zshrc
echo 'eval "$(mise activate zsh)"' >> ~/.zshrc
source ~/.zshrc
# For fish — add to ~/.config/fish/config.fish
echo 'mise activate fish | source' >> ~/.config/fish/config.fish
# Verify
mise --version
Basic Usage
# Install a tool at a specific version
mise install node@20
mise install python@3.12
mise install go@1.22
# Install the latest stable version
mise install node@latest
# Set the global default version
mise use --global node@20
mise use --global python@3.12
# Set a version for the current project (creates .mise.toml)
mise use node@20
mise use python@3.12
# List installed versions
mise list
# List all available versions of a tool
mise ls-remote node
# Show current active versions
mise current
Project Configuration with .mise.toml
Create a .mise.toml file in your project root to pin tool versions and define tasks:
[tools]
node = "20.11.0"
python = "3.12.2"
go = "1.22.0"
[env]
DATABASE_URL = "postgres://localhost/myapp_dev"
NODE_ENV = "development"
[tasks.dev]
run = "npm run dev"
description = "Start development server"
[tasks.test]
run = "npm test"
description = "Run test suite"
[tasks.lint]
run = "npm run lint && npm run typecheck"
description = "Lint and type-check the codebase"
[tasks.build]
run = "npm run build"
description = "Build for production"
When you cd into this directory, mise automatically activates Node 20.11.0, Python 3.12.2, and Go 1.22.0, and sets the environment variables.
Running Tasks
mise includes a built-in task runner. Define tasks in .mise.toml and run them with mise run:
# Run a task
mise run dev
mise run test
mise run build
# List available tasks
mise tasks
mise tasks ls
# Run with arguments
mise run test -- --watch
# Run multiple tasks
mise run lint && mise run test
Tasks support dependencies, file watching, and parallel execution:
[tasks.ci]
depends = ["lint", "test", "build"]
description = "Full CI pipeline"
[tasks.lint]
run = "eslint src/"
[tasks.test]
run = "jest --coverage"
[tasks.build]
run = "vite build"
Managing Multiple Projects
mise’s directory-based activation means you can have different versions active in different directories without any manual intervention:
cd ~/projects/legacy-app # uses Node 16, Python 3.9 (from .mise.toml)
node --version # v16.x.x
cd ~/projects/new-service # uses Node 22, Python 3.12 (from .mise.toml)
node --version # v22.x.x
Environment Variable Management
mise can manage per-project environment variables, eliminating the need for a separate .env tool:
[env]
APP_ENV = "development"
LOG_LEVEL = "debug"
DATABASE_URL = "postgres://localhost/myapp_dev"
# Reference other env vars
API_BASE_URL = "https://{{env.APP_ENV}}.api.example.com"
# View active environment
mise env
# Export env vars for use in a script
eval "$(mise env)"
💡 Tips & Tricks
Tip 1: Install All Tools Defined in .mise.toml
When you clone a project, one command installs all required tool versions:
mise install
Tip 2: Trust Configuration Files
mise requires you to trust .mise.toml files before executing them (a security feature):
mise trust
# or trust all files in the current directory and below:
mise trust --all
Tip 3: Use Fuzzy Version Matching
You don’t have to pin an exact version. mise supports fuzzy matching:
[tools]
node = "20" # latest 20.x.x
python = "3.12" # latest 3.12.x
ruby = "latest" # always latest stable
Tip 4: Shims vs. PATH Activation
mise can work in two modes — PATH activation (recommended, via eval "$(mise activate)") or shim-based (for editor integration):
# Generate shims for editors that don't source your shell profile
mise reshim
Tip 5: Upgrade All Tools at Once
# Upgrade all tools to their latest matching versions
mise upgrade
Tip 6: Check for Outdated Tools
mise outdated
Advanced Applications
CI/CD Integration
mise works great in CI pipelines, ensuring the same tool versions used locally are used in CI:
# .github/workflows/ci.yml
steps:
- uses: actions/checkout@v4
- uses: jdxcode/mise-action@v2 # official GitHub Action
with:
mise_toml: .mise.toml
- run: mise run ci
Or without the action:
# In your CI script
curl https://mise.run | sh
export PATH="$HOME/.local/bin:$PATH"
mise install
mise run test
mise run build
Migrating from nvm, pyenv, or rbenv
If you are currently using nvm, pyenv, or rbenv, migration is straightforward:
# Check which version you currently use
nvm current # e.g. v20.11.0
pyenv version # e.g. 3.12.2
# Set those versions globally in mise
mise use --global node@20.11.0
mise use --global python@3.12.2
# Remove old tools from your shell profile
# (remove nvm/pyenv/rbenv init lines from ~/.bashrc, ~/.zshrc)
mise reads existing .tool-versions files (the asdf format), so asdf users get immediate compatibility without any changes to their existing configuration files.
Related Resources
Related Tools
tmux— terminal multiplexer for running long-lived development sessions.direnv— similar per-directory env var management (can be used alongsidemise).asdf— the original polyglot version manager thatmiseis compatible with.
Real-world Use Cases
- Monorepo teams — each sub-package specifies its own tool versions in
.mise.toml, and developers automatically get the right versions without any manual steps. - Onboarding new developers — run
mise installonce after cloning, and all required language runtimes are installed and active immediately. - CI/CD pipelines — pin exact tool versions in
.mise.tomland use the officialmise-actionfor perfectly reproducible CI builds. - Multiple active projects — switch between a Node 16 legacy app and a Node 22 new service just by changing directories.
- Task standardization — replace scattered
Makefile,package.json scripts, andRakefilewith unifiedmise runtasks shared across all projects.
When Not To Use mise
- Production servers — use OS package managers or Docker images for server-side runtime installation;
miseis a development tool. - System-wide tools — tools like
git,curl, ordockerare better managed by the OS package manager. - Containers — inside a Docker container, pin versions in the
Dockerfiledirectly rather than usingmise. - Windows without WSL —
misehas limited Windows support; WSL2 is the recommended path for Windows users.
Practical Examples: Manage Dev Environments with mise
# 1. Set up a new project with pinned tool versions and tasks
cat > .mise.toml << 'EOF'
[tools]
node = "20.11.0"
python = "3.12.2"
[env]
NODE_ENV = "development"
[tasks.dev]
run = "node server.js"
[tasks.test]
run = "node --test"
EOF
mise install # install all pinned tools
mise run dev # start the dev server
# 2. Verify all team members are using the same versions
mise current
# node 20.11.0 .mise.toml
# python 3.12.2 .mise.toml
# 3. Run the full CI pipeline locally
mise run lint && mise run test && mise run build