はじめに
最近 mise を入れて、ruby を global に設定する…ということだけはやってみたものの、
- これって npm / yarn / pnpm みたいなもの?
- 「生で(直接)Ruby を入れる」のと何が違うの?
- そもそも何のために存在してるんだ…?
と、いまいち腑に落ちていませんでした。同じように「とりあえず入れたけど正体がわからん」という人は多そうなので、調べながら自分の理解を整理してみます。
結論だけ先に言うと、mise / asdf は npm / yarn / pnpm とは"層"が違うツールでした。
まず結論:mise / asdf は「言語のバージョン管理ツール」
ここが最初の勘違いポイントでした。npm などと名前が似ているので同じ仲間に見えますが、担当している仕事がそもそも違います。
| ツール | カテゴリ | 何を管理する? | 例えるなら |
|---|---|---|---|
| mise / asdf | バージョン管理(version manager) | 言語そのもののバージョン(Ruby 3.3 / Node 22 / Python 3.12 …) | 棚に「どの世代の道具一式」を置くか選ぶ係 |
| npm / yarn / pnpm | パッケージ管理(package manager) | プロジェクトが使うライブラリ(rails, react, lodash …) | 選んだ道具で作る作品に「どの部品」を使うか選ぶ係 |
[ OS ]
└─ mise / asdf … 言語ランタイムのバージョンを切り替える ← この層
└─ Ruby 3.3 / Node 22 / Python 3.12
└─ npm / yarn / pnpm / bundler … ライブラリを入れる ← この層
└─ rails, react, ...(プロジェクトの中身)
なので「mise はフレームワーク版の npm 的なもの?」という問いには、No、別の階層を担当している兄弟みたいなもの、というのが答えになります。
npm / yarn / pnpm は何をしている?
ここも整理しておきます。npm yarn pnpm は 3つとも同じ仕事(= Node のパッケージ管理)をする別実装です。「どれを使ってもやることは同じ、速さや使い勝手が違う」くらいの関係。
-
package.jsonに書かれた依存ライブラリをnode_modulesに入れる - これは Node の世界の中だけの話
Ruby でいう bundler(Gemfile を見て gem を入れる)、Python でいう pip がこのポジションです。
つまり「言語ごとにパッケージ管理ツールがある」わけで、mise はそのさらに一段下で、言語そのものを面倒見ているイメージです。
「生で Ruby を入れる」と何がまずいのか
ここが一番知りたかったところ。brew install ruby や OS 標準の Ruby をそのまま使う=「生で入れる」とどうなるか。普段の趣味開発なら困らないことも多いのですが、こういう場面で詰まりやすいです。
1. OS が使っている Ruby を壊しかねない
macOS や一部の Linux には、システム自身が使う Ruby が最初から入っています。これに sudo gem install ... で global に gem を入れたりバージョンをいじったりすると、OS のツールが動かなくなることがあります。触らないのが無難です。
2. プロジェクトごとにバージョンが違うと詰む
- プロジェクト A は Ruby 3.1 想定
- プロジェクト B は Ruby 3.3 想定
生で 1 個だけ入れていると、両方を行き来するたびに入れ直し…となります。バージョン管理ツールならディレクトリを移動するだけで自動で切り替わるので、これが効きます。
3. チームや CI と環境が揃わない
「自分のマシンでは動くのに本番(や同僚の環境)で動かない」の典型原因がバージョン差です。後述の設定ファイルをリポジトリに置いておけば、全員・CI が同じバージョンを使うよう揃えられます。
4. sudo / 権限まわりが面倒
生で global に入れると権限で詰まりがち。mise などは自分のホームディレクトリ配下にインストールするので、基本 sudo 不要で、消すのもフォルダごとで済みます。
まとめると「生で入れるのが常にダメ」ではなく、複数バージョン・チーム開発・環境を汚したくないといった場面で効いてくる、という理解になりました。
mise の global と local(ここが本体)
自分は global にしか設定していませんでしたが、mise の真価は local(プロジェクト単位)にあります。
global = 自分のマシン全体のデフォルト
# どこにいてもこの Ruby を使う(自分のデフォルト)
mise use -g ruby@3.3
設定は ~/.config/mise/config.toml に書かれます。「とりあえず Ruby 使いたい」段階ならこれで十分。
local = プロジェクトごとに固定
# プロジェクトのディレクトリに移動してから
cd my-app
mise use ruby@3.3
このコマンドで、カレントディレクトリに mise.toml が作られます(中身はこんな感じ)。
[tools]
ruby = "3.3"
このファイルを Git にコミットして共有すれば、
- そのディレクトリに入った瞬間、自動で Ruby 3.3 に切り替わる
- 別プロジェクトに移れば、そっちで指定されたバージョンに切り替わる
- 同僚も CI も同じバージョンになる
…という、まさに「何のためにあるのか」の答えがここでした。global しか触っていないと、この一番おいしい部分を使っていなかったわけです。
よく使うコマンドだけまとめ
# インストールできるバージョン一覧を見る
mise ls-remote ruby
# バージョンを指定してインストール
mise install ruby@3.3.0
# プロジェクトに固定(mise.toml を作成)
mise use ruby@3.3
# 自分のデフォルトにする(global)
mise use -g ruby@3.3
# 今どのバージョンが効いているか確認
mise current
# 入っているもの一覧
mise ls
ruby のところを node python go などに変えれば、同じ操作で全部の言語を管理できるのも嬉しいポイントです(言語ごとに nvm / rbenv / pyenv を別々に覚えなくていい)。
asdf との関係 / mise が新しい理由
mise と asdf はやりたいことがほぼ同じ仲間です。
-
asdf:プラグイン方式で多言語のバージョンを管理する、定番ツール。設定ファイルは
.tool-versions。 -
mise:Rust 製で高速な後発ツール。asdf の
.tool-versionsも読めるので移行しやすい。さらに環境変数の管理(direnv 的)やタスク実行(make 的)まで担えるのが特徴。
新規で始めるなら mise、既存で asdf を使っているチームならそのまま asdf、くらいの温度感で良さそうです。mise は .ruby-version(rbenv)や .nvmrc(nvm)といった他ツールの設定ファイルも読めるので、共存もできます。
まとめ
- mise / asdf は「言語そのもののバージョン」を切り替えるツール。npm / yarn / pnpm(=ライブラリを管理するツール)とは層が違う。
- 「生で入れる」のは、システムを壊すリスク・プロジェクト間のバージョン差・チーム/CI との不一致があるときに困る。
- mise の本命は local(
mise.tomlをプロジェクトに置く)。global しか使っていなかったら、ぜひ local を試すと「なるほどこれか」となるはず。 - 1 つのツールで Ruby も Node も Python もまとめて管理できるのが地味に最高。
自分のように「とりあえず入れて global にしただけ」だった人は、次のプロジェクトで mise use ruby@x.x を打って mise.toml をコミットしてみると、存在意義が一気に腹落ちすると思います。
この記事は自分が調べながら理解した内容のまとめです。間違いやもっと良い使い方があればコメントで教えてもらえると嬉しいです🙏