Ruby や Node.js などの開発ツールのバージョン管理は、rbenv
や nodenv
などの *env 系ツールを経て、2019 年から asdf
を使っていました。環境変数の管理は、さらに前の 2014 年から direnv
を使っていました。
少し前から mise というツールが話題です。特に困っていたわけではありませんが、なんとなくの好奇心と、mise には direnv のような機能もあると聞いたので、ツールの数を減らすモチベーションもあって移行してみました。環境は macOS です。
mise とは
mise(ミーズ)は、開発ツールのバージョン管理と環境変数の管理を 1 つで行えるツールです。asdf 互換のランタイム管理に加えて、direnv 相当の環境変数管理機能も備えています。
使って感じた特徴は以下のとおりです。
.tool-versionsを参照できる(.ruby-version等は設定が必要。後述)mise.tomlで環境変数やタスクランナーも定義できる- 公式の mise.toml が参考になるかも
mise.local.tomlで .gitignore 前提のローカル設定を持てる。チーム開発で mise 導入前でも個人で先行導入できる- ツール管理の体験がよく整理されている
mise install一発で.tool-versionsのツールを全てインストールできるmise listで全ツールのバージョンと参照元ファイルを一覧確認できる
移行で行ったこと
公式ドキュメントに asdf からの移行方法 があるので、まずはこちらを参照してください。以下は私の環境での具体的な手順です。
1. Homebrew パッケージの変更
asdf と direnv をアンインストールし、mise をインストールしました。
$ brew uninstall --force asdf
$ brew uninstall --force direnv
$ brew install mise
2. zsh の設定変更
~/.zshenv から asdf の設定を全て削除しました。
-MY_ASDF_CONFIG_HOME="${XDG_CONFIG_HOME}/asdf"
-export ASDF_CONFIG_FILE="${MY_ASDF_CONFIG_HOME}/asdfrc"
-export ASDF_DATA_DIR="${XDG_DATA_HOME}/asdf"
-export ASDF_GEM_DEFAULT_PACKAGES_FILE="${MY_ASDF_CONFIG_HOME}/default-gems"
-export ASDF_NPM_DEFAULT_PACKAGES_FILE="${MY_ASDF_CONFIG_HOME}/default-npm-packages"
-export ASDF_PERL_DEFAULT_PACKAGES_FILE="${MY_ASDF_CONFIG_HOME}/default-perl-modules"
-export ASDF_PYTHON_DEFAULT_PACKAGES_FILE="${MY_ASDF_CONFIG_HOME}/default-python-packages"
-export ASDF_RUBY_BUILD_VERSION=master
-PATH=$ASDF_DATA_DIR/shims:$PATH
~/.zshrc から direnv の設定も削除しました。
-eval "$(direnv hook zsh)"
代わりに ~/.zshrc に mise の設定を追加しました。この設定によって有効化される仕組みが PATH 管理を行うため、~/.zshenv への設定は不要です。
eval "$(mise activate zsh)"
実際のファイルは以下になります。
asdf 時代の環境変数がなくなり、zsh の設定がスッキリしました。
3. ツールのインストール
mise install で asdf が管理していたツールをインストールし直しました。
$ cat ~/.tool-versions
nodejs 24.14.0
ruby 4.0.2
$ mise install
$ mise list
Tool Version Source Requested
node 24.14.0 ~/.tool-versions 24.14.0
ruby 4.0.2 ~/.tool-versions 4.0.2
4. default_packages_file の移行
asdf では ~/.zshenv の環境変数で管理していた default_packages_file を、mise では ~/.config/mise/config.toml に集約してみました。
[settings.node]
default_packages_file = "~/.config/mise/default-npm-packages"
[settings.ruby]
default_packages_file = "~/.config/mise/default-gems"
なお移行中に、Node.js の default_packages_file で ~ が展開されず default packages がインストールされないバグを見つけました。Discussion#8606
に報告したところ、PR #8709
で修正されていました 🙏 v2026.3.11
以降であれば問題ありません。
5. .ruby-version や .node-version の参照設定
asdf も mise も、デフォルトでは .ruby-version や .node-version を参照しません。asdf では asdfrc に legacy_version_file = yes を設定しますが、mise では以下の設定が必要です。リポジトリの mise.toml や mise.local.toml に設定しました。
[settings]
idiomatic_version_file_enable_tools = ["node", "ruby"]
移行しなかったもの
いくつかの設定は移行不要、または移行しない判断をしました。
- Ruby の pre-install hook
- asdf では
pre_asdf_install_rubyでRUBY_CONFIGURE_OPTSを設定していたが、mise では設定しなくても大丈夫そうだった
- asdf では
ASDF_RUBY_BUILD_VERSION=master- mise は Ruby インストール時に ruby-build の最新バージョンを自動取得する ため設定不要だった
- perl の default-perl-modules
- mise は perl の
default_packages_fileを未サポートだった(対処方法は後述の付録参照)
- mise は perl の
- direnvrc の PATH_add
-
Gemfile.lock がある Ruby プロジェクトで
./binを PATH に自動追加する設定をしていた -
mise にグローバルな同等機能はないが、必要になったときに各プロジェクトの
mise.tomlで以下の設定をする方針とした[env] _.path = "./bin"
-
まとめ
asdf + direnv の 2 ツールを mise 1 つに置き換えました。zsh の設定がスッキリしたのと、ツールバージョンと環境変数を mise.toml に集約できるのが良いところです。
後述の付録に書いた Emacs との相性問題などハマりどころはありましたが、総合的には移行してよかったと思います。
また、direnv が不要になったことで .envrc から .env に移行でき、後日 .env を 1Password Environments
でマウントする構成にもつなげられました。
参考情報
- mise Getting Started
- miseは便利: タスクランナー兼ツールバージョン管理&環境変数管理ツール - TechRacho
- 1Password Environments
- 1Password Environmentsで.envファイルを管理できるようになったので試してみた - DevelopersIO
付録
Emacs で ruby-lsp が動作しない問題への対応
グローバルと異なる Ruby バージョンのリポジトリで、ruby-lsp が Emacs 上で動作しない問題に遭遇しました。
mise activate zsh はフックベースのアプローチで、ディレクトリ移動時に zsh の chpwd フックが発火してツールのバージョンを切り替えます。しかし Emacs はこのフックを実行しないため、mise のバージョン切り替えが機能しません。
mise にはフックベースの activate とは別に、shims という方式があります。
| activate | shims | |
|---|---|---|
| 向いている環境 | インタラクティブシェル | 非インタラクティブ(IDE、Emacs、スクリプト) |
cd などのフック |
発火する | 発火しない |
which の結果 |
実際のツールのパスを返す | shim のパスを返す |
最初は ~/.zshrc に eval "$(mise activate zsh --shims)" を追加して両方を有効にしましたが、mise のドキュメント
では activate と shims は排他的な使用を想定しています。
最終的には、以下の構成に落ち着きました。
eval "$(mise activate zsh)"は~/.zshrcに配置(インタラクティブシェル用)- Emacs 起動時のみ shims ディレクトリを PATH に追加
alias emacs="LC_COLLATE=C PATH='${XDG_DATA_HOME}/mise/shims:$PATH' emacs"
通常の zsh セッションはフックベースのみ、Emacs 起動時だけ shims を使うという役割分担です。
asdf は shims のみのシンプルな設計だったので、一見すると複雑になったように見えます。しかしこれは mise が asdf の代替だけでなく、direnv の代替でもあることに起因するトレードオフだと理解しました。mise activate により環境変数の変更がリアルタイムでインタラクティブシェルに反映されるのは、shims では実現できない機能です。
perl の default-packages への対処方法
mise の default-packages の仕組みはコアプラグイン(Go, Node.js, Python, Ruby)にハードコードされた言語固有の機能です。Perl はコアプラグインではなく、Aqua バックエンド経由でインストールされるため対象外です。
回避策として mise.toml の [hooks] postinstall で cpanm を実行する方法があります1。これにより mise install だけで Perl と CPAN モジュールの両方をセットアップできます。
[settings]
experimental = true
[hooks]
postinstall = "cpanm CGI HTML::Template"
注意点として、hooks は experimental 機能のため experimental = true が必要です。また postinstall は perl 以外のツールインストール時にも実行されるため、mise install のたびにこの hooks がトリガーされます。
mise と aqua との関係
aqua
は CLI ツール(terraform、gh 等)のバージョン管理に特化したツールで、checksum 検証によるセキュリティが充実しています。mise とはカバー範囲が異なりますが、mise は aqua-registry をバックエンドとして利用できる(aqua: プレフィックス)ため、aqua が管理するツール群も mise からインストールできます。
イコールではないものの、個人の dotfiles 管理では mise だけで aqua 的な用途も十分カバーできると感じました。チームで aqua を採用していたり、CI/CD でサプライチェーン対策として checksum 検証が必要な場合は、aqua を別途使う価値があると思います。