Use when: user mentions mise, rtx, .mise.toml, mise.toml, mise install, mise use, mise tasks, mise activate, mise hooks, polyglot tool version management, replacing asdf/nvm/pyenv/rbenv/direnv, managing multiple language runtimes in one project, project-level tool pinning, or CI/CD with jdx/mise-action. Also use when configuring .tool-versions with mise, mise backends, mise env vars, or mise task runner. Do NOT use when: user asks about Docker/container orchestration, Kubernetes, Terraform/OpenTofu provisioning, Ansible/Chef/Puppet config management, generic shell scripting unrelated to mise, npm/pip/cargo as standalone package managers (not as mise backends), or asdf without any mention of mise or migration intent.
Mise is a single binary (Rust) that replaces asdf, nvm, pyenv, rbenv, direnv, and Makefiles.
It manages tool versions, environment variables, and tasks per-project via .mise.toml.
Formerly named "rtx". Runs on macOS, Linux, and WSL. Written by @jdx.
Key capabilities:
.node-version, .python-version, .ruby-version, .tool-versions, .nvmrcjdx/mise-actionInstall mise:
curl https://mise.run | sh
Alternative methods:
brew install mise # macOS Homebrew
apt install mise # Debian/Ubuntu (after adding repo)
yay -S mise # Arch AUR
cargo install mise # From source
Mise does NOT work without shell activation. Add ONE of these:
Bash — append to ~/.bashrc:
eval "$(mise activate bash)"
Zsh — append to ~/.zshrc:
eval "$(mise activate zsh)"
Fish — append to ~/.config/fish/config.fish:
mise activate fish | source
Restart shell or source the config file. Verify:
mise --version
mise doctor # diagnose configuration issues
mise use node@20 # install node 20.x, pin in .mise.toml (local)
mise use -g [email protected] # install python 3.12, set as global default
mise install # install all tools defined in .mise.toml
mise install node@22 # install without activating
mise ls # list installed tools and active versions
mise ls-remote node # list all available node versions
mise outdated # show tools with newer versions available
mise upgrade # upgrade all tools to latest within constraints
mise uninstall node@18 # remove a specific version
mise prune # remove unused tool versions
.mise.toml in current directory (highest priority).mise.toml in parent directories (walking up)~/.config/mise/config.toml (global).node-version, .python-version, .tool-versions)mise use [email protected] [email protected] [email protected]
# Creates/updates .mise.toml:
# [tools]
# node = "20.11.0"
# python = "3.12"
# terraform = "1.7"
Central config file. Place in project root. Commit to version control.
min_version = "2025.1.0"
[tools]
node = "20" # latest 20.x
python = "3.12.2" # exact version
go = "latest" # latest stable
ruby = ["3.3.0", "3.2.2"] # multiple versions (first is default)
terraform = "1.7" # latest 1.7.x
erlang = "26"
elixir = "1.16"
[tools.java]
version = "21"
options = { provider = "temurin" } # tool-specific options
[env]
NODE_ENV = "development"
DATABASE_URL = "postgresql://localhost/devdb"
_.file = ".env" # source .env file
_.path = ["./node_modules/.bin", "./bin"] # prepend to PATH
[tasks]
build = "npm run build"
test = "npm test"
lint = "eslint src/"
[tasks.dev]
description = "Start dev server"
run = "npm run dev"
depends = ["build"]
[tasks.ci]
description = "Full CI pipeline"
depends = ["lint", "test", "build"]
run = "echo 'CI passed'"
[settings]
legacy_version_file = true # read .node-version, .python-version, etc.
always_keep_download = false
~/.config/mise/config.toml — global.mise.toml — project (committed).mise.local.toml — local overrides (gitignored).mise/config.toml — alternative project locationmise.<ENV>.toml — environment-specific[env]
NODE_ENV = "development"
API_URL = "http://localhost:3000"
SECRET_KEY = "dev-only-key"
# Template syntax (tera templates)
PROJECT_ROOT = "{{ config_root }}"
PATH_ADDITION = "{{ env.HOME }}/.local/bin"
# Source external files
_.file = [".env", ".env.local"]
# Prepend to PATH
_.path = ["./node_modules/.bin", "./scripts"]
.mise.toml [env] overrides shell env; .mise.local.toml overrides .mise.toml_.file values loaded in order; later files override earlier_.source to run a script and capture exported variables# mise.production.toml
[env]
NODE_ENV = "production"
DATABASE_URL = "postgresql://prod-host/proddb"
LOG_LEVEL = "warn"
Activate with: MISE_ENV=production mise run deploy
Define in .mise.toml:
[tasks.build]
description = "Build the application"
run = "cargo build --release"
alias = "b" # mise b
[tasks.test]
description = "Run tests"
run = ["cargo test", "./scripts/integration.sh"] # sequential commands
env = { RUST_LOG = "debug" } # per-task env vars
dir = "{{config_root}}" # working directory
[tasks.deploy]
description = "Deploy to production"
depends = ["build", "test"] # run deps first (parallel when possible)
run = "./deploy.sh"
[tasks.watch]
description = "Watch and rebuild"
run = "cargo watch -x build"
[tasks.format]
description = "Format all code"
run = '''
cargo fmt
prettier --write "src/**/*.{ts,tsx}"
'''
Run tasks:
mise run build # or just: mise build
mise run test -- -v # pass args after --
mise run # interactive task selector (no args)
mise tasks # list all available tasks
Create executable scripts in .mise/tasks/:
#!/usr/bin/env bash
# mise description="Database migration"
# mise depends=["build"]
# mise alias="db:migrate"
set -euo pipefail
echo "Running migrations..."
./scripts/migrate.sh "$@"
File name becomes task name. Metadata via # mise comments.
[tasks.deploy]
depends = [
{ task = "build", args = ["--release"] },
{ task = "test", env = { CI = "true" } }
]
run = "./deploy.sh"
Mise uses backends to install tools. Priority order:
| Backend | Use Case | Syntax |
|---|---|---|
| core | Built-in (Node, Python, Go, Ruby, Java, Erlang, etc.) | node, python |
| aqua | GitHub releases via aqua registry (preferred for new tools) | aqua:cli/cli |
| github | Direct GitHub release binaries (replaced ubi) | github:owner/repo |
| cargo | Rust crates | cargo:ripgrep |
| npm | Node packages | npm:prettier |
| pipx | Python CLI tools (isolated envs) | pipx:black |
| go | Go modules | go:golang.org/x/tools/gopls |
| asdf | asdf plugins (legacy fallback) | asdf:plugin-name |
[tools]
node = "20" # core backend (automatic)
"npm:prettier" = "3" # npm backend
"cargo:ripgrep" = "14" # cargo backend
"aqua:cli/cli" = "2.45" # aqua backend for GitHub CLI
"pipx:black" = "24" # pipx backend
"go:golang.org/x/tools/gopls" = "latest" # go backend
mise settings set disable_backends asdf # disable asdf backend globally
Mise reads existing version files automatically (when legacy_version_file = true, which is default):
| File | Tool |
|---|---|
.node-version, .nvmrc | Node.js |
.python-version | Python |
.ruby-version | Ruby |
.go-version | Go |
.java-version | Java |
.tool-versions | Any (asdf format) |
No migration required — mise reads these alongside .mise.toml. When both exist, .mise.toml takes precedence.
Hooks run shell commands on directory events. Require mise activate.
[hooks]
enter = "echo 'Entered project'" # once on first cd into project
leave = "echo 'Left project'" # when leaving project tree
cd = "echo 'Changed to {{cwd}}'" # every cd within project
enter = { task = "setup" } # run a mise task as hook
Configure via mise settings set KEY VALUE or in [settings]:
[settings]
legacy_version_file = true # read .node-version, .python-version, etc.
always_keep_download = false # delete tarballs after install
plugin_autoupdate_last_check_duration = "7d"
jobs = 4 # parallel install jobs
raw = false # show raw install output
yes = false # auto-confirm prompts
mise settings ls # list all settings and values
mise settings set jobs 8 # set parallel jobs
| Feature | mise | asdf | nvm | pyenv | direnv |
|---|---|---|---|---|---|
| Multi-language | ✅ | ✅ | ❌ | ❌ | ❌ |
| Env vars | ✅ | ❌ | ❌ | ❌ | ✅ |
| Task runner | ✅ | ❌ | ❌ | ❌ | ❌ |
| Performance | Fast (Rust) | Slow (Bash) | Medium | Medium | Fast |
| Legacy compat | ✅ | N/A | N/A | N/A | N/A |
| Single binary | ✅ | ❌ | ❌ | ❌ | ✅ |
Mise is a drop-in replacement for asdf with better performance and more features. It reads .tool-versions natively — just install mise and activate.
.mise.toml to the repocurl https://mise.run | sh # install mise
eval "$(mise activate bash)" # activate (add to shell rc)
mise install # install all project tools
mise run setup # run project setup task (if defined)
repo/
├── .mise.toml # shared tools (node, python)
├── services/
│ ├── api/.mise.toml # api-specific (go, extra env vars)
│ └── web/.mise.toml # web-specific (node version override)
Child .mise.toml files inherit and override parent settings.
.mise.local.toml
mise.local.toml
jdx/mise-action