2 Software mise
Drew edited this page 2026-07-26 21:30:33 -04:00

mise

mise gives every project the current version of its language toolchain — Hugo, Go, Node, Rust, Python, Zig — pulled straight from upstream, never from Debian's months-behind apt. No root, no version conflicts, nothing in your repo but a tiny mise.toml.


Why bother — the gap is not small

Debian ships stable, then freezes; upstream dev tools ship weekly. By mid-release-cycle a Trixie box is months to years behind, and tutorials assume the new version. Measured on Debian 13 (Trixie):

Tool apt install mise use …@latest Behind by
Hugo 0.131.0 0.162.1 31 releases
Go 1.24 1.26.3 2 minor
Node 20.19 26.2 6 major
Rust 1.85.0 1.96.0 11 releases
Python 3.13.5 3.14.5 a full minor
Zig not packaged 0.17-dev apt can't help you

The build errors a beginner blames on themselves are almost always just an old apt package. With mise your Debian is never versions behind, and mise upgrade keeps it there.

The trick, in one line: point at upstream's repo, don't mirror it. mise itself comes from apt and updates with apt upgrade; the toolchains it manages come from each tool's own upstream and update with mise upgrade. They never touch each other.


Install

mise has a signed apt repo, so it updates with the rest of your system. Paste this as one unit:

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg

sudo install -dm755 /etc/apt/keyrings
curl -fsSL https://mise.jdx.dev/gpg-key.pub \
    | sudo gpg --dearmor -o /etc/apt/keyrings/mise-archive-keyring.gpg
sudo chmod 644 /etc/apt/keyrings/mise-archive-keyring.gpg

echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.gpg arch=amd64] https://mise.jdx.dev/deb stable main" \
    | sudo tee /etc/apt/sources.list.d/mise.list

sudo apt-get update
sudo apt-get install -y mise

Prefer one command? The install + shell activation below are bundled into an idempotent install_mise.sh in butterscripts (setup/install_mise.sh). Re-run it anytime; it skips what's already done.


Activate it — ⚠ the #1 thing people get wrong

Installing the package does not change your PATH. mise hooks into your shell to switch tool versions on and off, so you turn it on once.

Activation is shell-specific. mise activate bash only works in bash; mise activate zsh only works in zsh. Wire up bash while your terminal actually runs zsh and your tools silently never appear — zsh even throws no such hash table element: _mise_hook. Match your login shell, not whatever's running right now:

basename "$(getent passwd "$USER" | cut -d: -f7)"   # -> bash or zsh

Add the matching hook to the matching rc file, then reload your login shell:

echo 'eval "$(mise activate bash)"' >> ~/.bashrc    # or 'zsh' into ~/.zshrc
exec "$(basename "$(getent passwd "$USER" | cut -d: -f7)")"

If you recently ran chsh, your desktop session keeps the old shell until you log out and back in — a new terminal tab is not enough. Then confirm with mise doctor (should report activated: yes).


Use a project

The whole model in one sentence: a project is just a directory with a mise.toml. There's no "create" command — you make a folder and pin tools. mise turns the right versions on when you cd in, off when you leave.

mkdir ~/code/myapp && cd ~/code/myapp

# Pin the tools this project needs — writes ./mise.toml AND installs them.
# List every tool you want; pinning one does NOT pin the others.
mise use node@lts go@latest

git add mise.toml && git commit -m "pin toolchain with mise"

mise.toml is the lockfile for your toolchain — commit it. The binaries live under ~/.local/share/mise/ (per-user, no root), never in the repo. Someone who clones the repo gets the exact same toolchain with two commands:

mise trust       # one-time: OK this config (it wasn't written on this box)
mise install     # fetch every tool/version listed in mise.toml

Command reference

Command What it does
mise use <tool>@<ver> Pin a tool in the current dir's mise.toml and install it
mise use -g <tool>@<ver> Set a global default for when you're not in a project
mise install Install everything listed in the local mise.toml (the clone handoff)
mise trust Trust this dir's mise.toml so mise auto-loads it (--all to stop asking)
mise ls --current List tools active right here and which file pins them
mise outdated Show tools with a newer upstream release
mise upgrade Bump tools to the newest version your pins allow
mise doctor Diagnose activation + config problems

Troubleshooting

None of these are mise bugs — just easy ways to think it failed.

  1. Wrong shell / changed shell without re-login. The most common one — see the activation warning above. echo "$SHELL" vs the getent line; if they disagree, log out and back in.
  2. command not found for a tool you "installed". mise only puts a tool on PATH inside a dir whose mise.toml pins it. mise use node@lts pins node only — pin everything you want in one go: mise use node@lts go@latest zig@latest.
  3. Config files … are not trusted. A safety feature, not an error — run mise trust once in a project you own. Don't blindly trust configs you didn't write.

When in doubt, mise doctor reports whether activation is live and what's wrong.


Uninstall

Leaves the machine as it was:

sudo apt-get remove --purge -y mise
sudo rm -f /etc/apt/sources.list.d/mise.list /etc/apt/keyrings/mise-archive-keyring.gpg
sudo apt-get update

sed -i '/mise activate/d' ~/.bashrc ~/.zshrc 2>/dev/null
rm -rf ~/.local/share/mise ~/.config/mise
exec "$(basename "$(getent passwd "$USER" | cut -d: -f7)")"