Migrating from asdf to mise

Tadashi Shigeoka ·  Sun, February 1, 2026

I migrated from asdf to mise for managing runtime versions. Since mise has built-in environment variable management, I also removed direnv.

Why I Chose mise

asdf has been my go-to version manager for a long time, but I decided to switch after discovering mise, a faster alternative built in Rust. For a detailed comparison, see the official mise comparison page.

Comparing asdf and mise

Aspectasdfmise
ImplementationShell scriptsRust
Command executionShims (~120ms overhead)Direct PATH updates (~5–10ms)
Tool installation3-step process: add plugin → install → setSingle mise use command
Config files.tool-versions.tool-versions / mise.toml
Environment variablesNot supportedBuilt-in support
Task runnerNot supportedBuilt-in support

Migration Steps

The recommended approach is to install mise first, verify your tools work, and then uninstall asdf. This order is also recommended by the mise FAQ, ensuring zero downtime during the migration.

1. Install mise

Following the official documentation, install mise via Homebrew:

brew install mise

2. Configure your shell

Remove the asdf-related configuration (such as . $(brew --prefix asdf)/libexec/asdf.sh) from your .zshrc, then add mise activation:

echo 'eval "$(mise activate zsh)"' >> ~/.zshrc

Note: Do not activate both asdf and mise simultaneously. Remove the asdf line from .zshrc before adding the mise line.

Apply the configuration:

source ~/.zshrc

3. Install your tools

mise does not carry over tools installed by asdf, so you’ll need to reinstall them. If your project already has a .tool-versions file, simply run the following in that directory:

mise install

This will install all tools listed in .tool-versions at once.

4. Verify the setup

Confirm that your tools are running through mise:

mise doctor
node -v
which node  # Should point to ~/.local/share/mise/installs/node/...

5. Uninstall asdf

Once you’ve confirmed everything works with mise, uninstall asdf:

brew uninstall asdf --force

Removing direnv

mise has built-in environment variable management, making direnv unnecessary. The mise documentation also officially discourages using direnv alongside mise.

Uninstall direnv

brew uninstall direnv

Remove the direnv-related configuration (such as eval "$(direnv hook zsh)") from your .zshrc as well.

Managing environment variables with mise

Settings previously written in .envrc for direnv can be migrated to mise.toml in your project:

[env]
DATABASE_URL = "postgres://localhost/mydb"
NODE_ENV = "development"
 
# Load .env files
_.file = ".env"
 
# Add to PATH
_.path = "./bin"

mise.toml is automatically applied when you enter the directory and removed when you leave — the same behavior as direnv.

Comparing direnv and mise environment management

Aspectdirenvmise
Config file.envrc (shell script)mise.toml (TOML)
.env loadingdotenv .env_.file = '.env'
PATH additionsPATH_add ./bin_.path = './bin'
Python venvlayout python_.python.venv = { path = ".venv", create = true }
Script executionWritten directly in .envrc_.source = "./script.sh"

Conclusion

Migrating from asdf to mise takes just a few commands with Homebrew. By setting up mise first and removing asdf afterward, you can migrate safely with zero downtime.

On top of that, mise’s built-in environment variable management makes direnv unnecessary, consolidating version management and environment configuration into a single tool.

That’s all from the Gemba, where we migrated from asdf and direnv to mise.